blob: 49c42ee93f6a0376c5772edc804a2c7c24d7bcbd [file] [log] [blame]
Robert Phillips96601082018-05-29 16:13:26 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tools/DDLPromiseImageHelper.h"
Robert Phillips96601082018-05-29 16:13:26 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkDeferredDisplayListRecorder.h"
Robert Phillips66944402019-09-30 13:21:25 -040011#include "include/core/SkPicture.h"
12#include "include/core/SkSerialProcs.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkYUVAIndex.h"
14#include "include/core/SkYUVASizeInfo.h"
Robert Phillipsd5f3c982020-07-07 13:18:47 -040015#include "include/gpu/GrDirectContext.h"
Brian Salomonbd3792d2020-11-10 14:17:58 -050016#include "include/gpu/GrYUVABackendTextures.h"
Brian Salomonefb5f072020-07-28 21:06:43 -040017#include "src/codec/SkCodecImageGenerator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/core/SkCachedData.h"
Mike Reed13711eb2020-07-14 17:16:32 -040019#include "src/core/SkMipmap.h"
Robert Phillips923181b2020-02-14 12:36:37 -050020#include "src/core/SkTaskGroup.h"
Adlai Hollera0693042020-10-14 11:23:11 -040021#include "src/gpu/GrDirectContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/image/SkImage_Base.h"
23#include "src/image/SkImage_GpuYUVA.h"
Robert Phillips96601082018-05-29 16:13:26 -040024
Robert Phillipsf95e2f42020-04-17 16:20:55 -040025DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(int index,
26 uint32_t originalUniqueID,
27 const SkImageInfo& ii)
28 : fIndex(index)
29 , fOriginalUniqueID(originalUniqueID)
30 , fImageInfo(ii) {
31}
32
33DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(PromiseImageInfo&& other)
34 : fIndex(other.fIndex)
35 , fOriginalUniqueID(other.fOriginalUniqueID)
36 , fImageInfo(other.fImageInfo)
37 , fBaseLevel(other.fBaseLevel)
38 , fMipLevels(std::move(other.fMipLevels))
Brian Salomon5660e8b2020-08-25 12:40:32 -040039 , fYUVAPixmaps(std::move(other.fYUVAPixmaps)) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040040 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040041 fCallbackContexts[i] = std::move(other.fCallbackContexts[i]);
42 }
43}
44
45DDLPromiseImageHelper::PromiseImageInfo::~PromiseImageInfo() {}
46
John Stilesec9b4aa2020-08-07 13:05:14 -040047std::unique_ptr<SkPixmap[]> DDLPromiseImageHelper::PromiseImageInfo::normalMipLevels() const {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040048 SkASSERT(!this->isYUV());
49 std::unique_ptr<SkPixmap[]> pixmaps(new SkPixmap[this->numMipLevels()]);
50 pixmaps[0] = fBaseLevel.pixmap();
51 if (fMipLevels) {
52 for (int i = 0; i < fMipLevels->countLevels(); ++i) {
Mike Reed13711eb2020-07-14 17:16:32 -040053 SkMipmap::Level mipLevel;
Robert Phillipsf95e2f42020-04-17 16:20:55 -040054 fMipLevels->getLevel(i, &mipLevel);
55 pixmaps[i+1] = mipLevel.fPixmap;
56 }
57 }
58 return pixmaps;
59}
60
61int DDLPromiseImageHelper::PromiseImageInfo::numMipLevels() const {
62 SkASSERT(!this->isYUV());
63 return fMipLevels ? fMipLevels->countLevels()+1 : 1;
64}
65
66void DDLPromiseImageHelper::PromiseImageInfo::setMipLevels(const SkBitmap& baseLevel,
Mike Reed13711eb2020-07-14 17:16:32 -040067 std::unique_ptr<SkMipmap> mipLevels) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040068 fBaseLevel = baseLevel;
69 fMipLevels = std::move(mipLevels);
70}
71
72///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips11c67672020-04-23 15:10:03 -040073PromiseImageCallbackContext::~PromiseImageCallbackContext() {
Brian Salomon72068172020-12-17 09:38:59 -050074 // See comment in release() about YUVA image creation failures.
75 // SkASSERT(fDoneCnt == fNumImages);1
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050076 SkASSERT(!fTotalFulfills || fDoneCnt);
Robert Phillips96601082018-05-29 16:13:26 -040077
Brian Salomon3f4cd772019-01-11 16:03:19 -050078 if (fPromiseImageTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040079 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
Robert Phillips96601082018-05-29 16:13:26 -040080 }
81}
82
Robert Phillips11c67672020-04-23 15:10:03 -040083void PromiseImageCallbackContext::setBackendTexture(const GrBackendTexture& backendTexture) {
Brian Salomon7d88f312019-02-28 10:03:03 -050084 SkASSERT(!fPromiseImageTexture);
Robert Phillips923181b2020-02-14 12:36:37 -050085 SkASSERT(fBackendFormat == backendTexture.getBackendFormat());
Brian Salomon3f4cd772019-01-11 16:03:19 -050086 fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050087}
88
Robert Phillipsd5f3c982020-07-07 13:18:47 -040089void PromiseImageCallbackContext::destroyBackendTexture() {
90 SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
91
92 if (fPromiseImageTexture) {
93 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
94 }
95 fPromiseImageTexture = nullptr;
96}
97
Robert Phillips96601082018-05-29 16:13:26 -040098///////////////////////////////////////////////////////////////////////////////////////////////////
99
100sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
101 SkSerialProcs procs;
102
103 procs.fImageCtx = this;
104 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
105 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
106
107 int id = helper->findOrDefineImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400108
Robert Phillips6bad7052019-12-16 15:09:57 -0500109 // Even if 'id' is invalid (i.e., -1) write it to the SKP
110 return SkData::MakeWithCopy(&id, sizeof(id));
Robert Phillips96601082018-05-29 16:13:26 -0400111 };
112
113 return inputPicture->serialize(&procs);
114}
115
Brian Salomonbd3792d2020-11-10 14:17:58 -0500116static GrBackendTexture create_yuva_texture(GrDirectContext* direct,
117 const SkPixmap& pm,
118 int texIndex) {
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500119 SkASSERT(texIndex >= 0 && texIndex <= 3);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400120
Greg Danielc1ad77c2020-05-06 11:40:03 -0400121 bool finishedBECreate = false;
122 auto markFinished = [](void* context) {
123 *(bool*)context = true;
124 };
Brian Salomonb5f880a2020-12-07 11:30:16 -0500125 auto beTex = direct->createBackendTexture(pm,
126 kTopLeft_GrSurfaceOrigin,
127 GrRenderable::kNo,
128 GrProtected::kNo,
129 markFinished,
130 &finishedBECreate);
Greg Danielc1ad77c2020-05-06 11:40:03 -0400131 if (beTex.isValid()) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400132 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400133 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400134 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400135 }
136 }
137 return beTex;
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500138}
139
Robert Phillips923181b2020-02-14 12:36:37 -0500140/*
141 * Create backend textures and upload data to them for all the textures required to satisfy
142 * a single promise image.
143 * For YUV textures this will result in up to 4 actual textures.
144 */
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400145void DDLPromiseImageHelper::CreateBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips923181b2020-02-14 12:36:37 -0500146 PromiseImageInfo* info) {
Robert Phillips923181b2020-02-14 12:36:37 -0500147 if (info->isYUV()) {
Brian Salomonbd3792d2020-11-10 14:17:58 -0500148 int numPixmaps = info->yuvaInfo().numPlanes();
Robert Phillips923181b2020-02-14 12:36:37 -0500149 for (int j = 0; j < numPixmaps; ++j) {
150 const SkPixmap& yuvPixmap = info->yuvPixmap(j);
151
152 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
153 SkASSERT(callbackContext);
154
Robert Phillips4508eb92020-04-15 15:54:34 -0400155 // DDL TODO: what should we do with mipmapped YUV images
Brian Salomonbd3792d2020-11-10 14:17:58 -0500156 callbackContext->setBackendTexture(create_yuva_texture(direct, yuvPixmap, j));
Robert Phillips923181b2020-02-14 12:36:37 -0500157 SkASSERT(callbackContext->promiseImageTexture());
158 }
159 } else {
160 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
161 if (!callbackContext) {
162 // This texture would've been too large to fit on the GPU
163 return;
164 }
165
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400166 std::unique_ptr<SkPixmap[]> mipLevels = info->normalMipLevels();
Robert Phillips923181b2020-02-14 12:36:37 -0500167
Greg Danielc1ad77c2020-05-06 11:40:03 -0400168 bool finishedBECreate = false;
169 auto markFinished = [](void* context) {
170 *(bool*)context = true;
171 };
Brian Salomonb5f880a2020-12-07 11:30:16 -0500172 auto backendTex = direct->createBackendTexture(mipLevels.get(),
173 info->numMipLevels(),
174 kTopLeft_GrSurfaceOrigin,
175 GrRenderable::kNo,
176 GrProtected::kNo,
177 markFinished,
178 &finishedBECreate);
Robert Phillips923181b2020-02-14 12:36:37 -0500179 SkASSERT(backendTex.isValid());
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400180 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400181 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400182 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400183 }
Robert Phillips923181b2020-02-14 12:36:37 -0500184
185 callbackContext->setBackendTexture(backendTex);
186 }
187}
188
Brian Salomonbd3792d2020-11-10 14:17:58 -0500189void DDLPromiseImageHelper::DeleteBETexturesForPromiseImage(PromiseImageInfo* info) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500190 if (info->isYUV()) {
Brian Salomonbd3792d2020-11-10 14:17:58 -0500191 int numPixmaps = info->yuvaInfo().numPlanes();
Robert Phillips19f466d2020-02-26 10:27:07 -0500192 for (int j = 0; j < numPixmaps; ++j) {
193 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
194 SkASSERT(callbackContext);
195
196 callbackContext->destroyBackendTexture();
197 SkASSERT(!callbackContext->promiseImageTexture());
198 }
199 } else {
200 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
201 if (!callbackContext) {
202 // This texture would've been too large to fit on the GPU
203 return;
204 }
205
206 callbackContext->destroyBackendTexture();
207 SkASSERT(!callbackContext->promiseImageTexture());
208 }
209}
210
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400211void DDLPromiseImageHelper::createCallbackContexts(GrDirectContext* direct) {
212 const GrCaps* caps = direct->priv().caps();
Robert Phillips923181b2020-02-14 12:36:37 -0500213 const int maxDimension = caps->maxTextureSize();
214
215 for (int i = 0; i < fImageInfo.count(); ++i) {
216 PromiseImageInfo& info = fImageInfo[i];
217
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400218 if (info.isYUV()) {
Brian Salomonbd3792d2020-11-10 14:17:58 -0500219 int numPixmaps = info.yuvaInfo().numPlanes();
Robert Phillips923181b2020-02-14 12:36:37 -0500220
Jim Van Verth8f11e432018-10-18 14:36:59 -0400221 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400222 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -0400223
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400224 GrBackendFormat backendFormat = direct->defaultBackendFormat(yuvPixmap.colorType(),
225 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500226
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400227 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400228 new PromiseImageCallbackContext(direct, backendFormat));
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500229
Robert Phillips923181b2020-02-14 12:36:37 -0500230 info.setCallbackContext(j, std::move(callbackContext));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400231 }
232 } else {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400233 const SkBitmap& baseLevel = info.baseLevel();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400234
Robert Phillips923181b2020-02-14 12:36:37 -0500235 // TODO: explicitly mark the PromiseImageInfo as too big and check in uploadAllToGPU
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400236 if (maxDimension < std::max(baseLevel.width(), baseLevel.height())) {
Robert Phillips923181b2020-02-14 12:36:37 -0500237 // This won't fit on the GPU. Fallback to a raster-backed image per tile.
238 continue;
239 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400240
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400241 GrBackendFormat backendFormat = direct->defaultBackendFormat(baseLevel.colorType(),
242 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500243 if (!caps->isFormatTexturable(backendFormat)) {
244 continue;
245 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400246
Robert Phillips923181b2020-02-14 12:36:37 -0500247 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400248 new PromiseImageCallbackContext(direct, backendFormat));
Robert Phillips923181b2020-02-14 12:36:37 -0500249
250 info.setCallbackContext(0, std::move(callbackContext));
251 }
252 }
253}
254
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400255void DDLPromiseImageHelper::uploadAllToGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips923181b2020-02-14 12:36:37 -0500256 if (taskGroup) {
257 for (int i = 0; i < fImageInfo.count(); ++i) {
258 PromiseImageInfo* info = &fImageInfo[i];
259
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400260 taskGroup->add([direct, info]() { CreateBETexturesForPromiseImage(direct, info); });
Robert Phillips923181b2020-02-14 12:36:37 -0500261 }
262 } else {
263 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400264 CreateBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400265 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500266 }
267}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400268
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400269void DDLPromiseImageHelper::deleteAllFromGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500270 if (taskGroup) {
271 for (int i = 0; i < fImageInfo.count(); ++i) {
272 PromiseImageInfo* info = &fImageInfo[i];
273
Brian Salomonbd3792d2020-11-10 14:17:58 -0500274 taskGroup->add([info]() { DeleteBETexturesForPromiseImage(info); });
Robert Phillips19f466d2020-02-26 10:27:07 -0500275 }
276 } else {
277 for (int i = 0; i < fImageInfo.count(); ++i) {
Brian Salomonbd3792d2020-11-10 14:17:58 -0500278 DeleteBETexturesForPromiseImage(&fImageInfo[i]);
Robert Phillips19f466d2020-02-26 10:27:07 -0500279 }
280 }
281}
282
Robert Phillips96601082018-05-29 16:13:26 -0400283sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
284 SkDeferredDisplayListRecorder* recorder,
285 SkData* compressedPictureData,
286 SkTArray<sk_sp<SkImage>>* promiseImages) const {
287 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
288
289 SkDeserialProcs procs;
290 procs.fImageCtx = (void*) &perRecorderContext;
Robert Phillips923181b2020-02-14 12:36:37 -0500291 procs.fImageProc = CreatePromiseImages;
Robert Phillips96601082018-05-29 16:13:26 -0400292
293 return SkPicture::MakeFromData(compressedPictureData, &procs);
294}
295
296// This generates promise images to replace the indices in the compressed picture. This
297// reconstitution is performed separately in each thread so we end up with multiple
298// promise images referring to the same GrBackendTexture.
Robert Phillips923181b2020-02-14 12:36:37 -0500299sk_sp<SkImage> DDLPromiseImageHelper::CreatePromiseImages(const void* rawData,
Robert Phillips96601082018-05-29 16:13:26 -0400300 size_t length, void* ctxIn) {
301 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
302 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
303 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
304
305 SkASSERT(length == sizeof(int));
306
307 const int* indexPtr = static_cast<const int*>(rawData);
Robert Phillips6bad7052019-12-16 15:09:57 -0500308 if (!helper->isValidID(*indexPtr)) {
309 return nullptr;
310 }
Robert Phillips96601082018-05-29 16:13:26 -0400311
312 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
313
Robert Phillips923181b2020-02-14 12:36:37 -0500314 // If there is no callback context that means 'createCallbackContexts' determined the
315 // texture wouldn't fit on the GPU. Create a separate bitmap-backed image for each thread.
316 if (!curImage.isYUV() && !curImage.callbackContext(0)) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400317 SkASSERT(curImage.baseLevel().isImmutable());
Mike Reeddc607e32020-12-23 11:50:36 -0500318 return curImage.baseLevel().asImage();
Robert Phillips96601082018-05-29 16:13:26 -0400319 }
Robert Phillips923181b2020-02-14 12:36:37 -0500320
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400321 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400322
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400323 sk_sp<SkImage> image;
324 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400325 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
Brian Salomonbd3792d2020-11-10 14:17:58 -0500326 const SkYUVAInfo& yuvaInfo = curImage.yuvaInfo();
Jim Van Verthe24b5872018-10-29 16:26:02 -0400327 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
Brian Salomonbd3792d2020-11-10 14:17:58 -0500328 int textureCount = yuvaInfo.numPlanes();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400329 for (int i = 0; i < textureCount; ++i) {
Robert Phillips923181b2020-02-14 12:36:37 -0500330 backendFormats[i] = curImage.backendFormat(i);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400331 contexts[i] = curImage.refCallbackContext(i).release();
332 }
Brian Salomonbd3792d2020-11-10 14:17:58 -0500333 GrYUVABackendTextureInfo yuvaBackendTextures(yuvaInfo,
334 backendFormats,
335 GrMipmapped::kNo,
336 kTopLeft_GrSurfaceOrigin);
Jim Van Verthf99a6742018-10-18 16:13:18 +0000337
Brian Salomon0cc57542019-03-08 13:28:46 -0500338 image = recorder->makeYUVAPromiseTexture(
Brian Salomonbd3792d2020-11-10 14:17:58 -0500339 yuvaBackendTextures,
Brian Salomon0cc57542019-03-08 13:28:46 -0500340 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400341 PromiseImageCallbackContext::PromiseImageFulfillProc,
342 PromiseImageCallbackContext::PromiseImageReleaseProc,
Brian Salomonf1432742020-11-09 15:40:27 -0500343 contexts);
Brian Salomon72068172020-12-17 09:38:59 -0500344 if (!image) {
345 return nullptr;
346 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500347 for (int i = 0; i < textureCount; ++i) {
348 curImage.callbackContext(i)->wasAddedToImage();
349 }
Robert Phillips193c4212019-03-04 12:18:53 -0500350
351#ifdef SK_DEBUG
352 {
353 // By the peekProxy contract this image should not have a single backing proxy so
354 // should return null. The call should also not trigger the conversion to RGBA.
355 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
356 SkASSERT(!yuva->peekProxy());
357 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
358 }
359#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400360 } else {
John Stiles31954bf2020-08-07 17:35:54 -0400361 const GrBackendFormat& backendFormat = curImage.backendFormat(0);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500362 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400363
364 // Each DDL recorder gets its own ref on the promise callback context for the
365 // promise images it creates.
Brian Salomonf1432742020-11-09 15:40:27 -0500366 image = recorder->makePromiseTexture(backendFormat,
367 curImage.overallWidth(),
368 curImage.overallHeight(),
369 curImage.mipMapped(0),
370 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
371 curImage.overallColorType(),
372 curImage.overallAlphaType(),
373 curImage.refOverallColorSpace(),
374 PromiseImageCallbackContext::PromiseImageFulfillProc,
375 PromiseImageCallbackContext::PromiseImageReleaseProc,
376 (void*)curImage.refCallbackContext(0).release());
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500377 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400378 }
Robert Phillips96601082018-05-29 16:13:26 -0400379 perRecorderContext->fPromiseImages->push_back(image);
380 SkASSERT(image);
381 return image;
382}
383
384int DDLPromiseImageHelper::findImage(SkImage* image) const {
385 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400386 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
387 SkASSERT(fImageInfo[i].index() == i);
388 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400389 return i;
390 }
391 }
392 return -1;
393}
394
395int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400396 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400397
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400398 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400399 image->colorType() == kBGRA_8888_SkColorType
400 ? kRGBA_8888_SkColorType
401 : image->colorType(),
402 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400403 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400404
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400405 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
406 image->uniqueID(),
407 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400408
Brian Salomonefb5f072020-07-28 21:06:43 -0400409 auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(ib->refEncodedData());
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400410 SkYUVAPixmapInfo yuvaInfo;
Brian Salomon59c60b02020-09-01 15:01:15 -0400411 if (codec && codec->queryYUVAInfo(fSupportedYUVADataTypes, &yuvaInfo)) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400412 auto yuvaPixmaps = SkYUVAPixmaps::Allocate(yuvaInfo);
413 SkAssertResult(codec->getYUVAPlanes(yuvaPixmaps));
Brian Salomon5660e8b2020-08-25 12:40:32 -0400414 SkASSERT(yuvaPixmaps.isValid());
415 newImageInfo.setYUVPlanes(std::move(yuvaPixmaps));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400416 } else {
417 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
Robert Phillipse84bffc2019-12-16 11:22:17 -0500418 if (!rasterImage) {
419 return -1;
420 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400421
422 SkBitmap tmp;
423 tmp.allocPixels(overallII);
424
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400425 if (!rasterImage->readPixels(nullptr, tmp.pixmap(), 0, 0)) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400426 return -1;
427 }
428
429 tmp.setImmutable();
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400430
431 // Given how the DDL testing harness works (i.e., only modifying the SkImages w/in an
432 // SKP) we don't know if a given SkImage will require mipmapping. To work around this
433 // we just try to create all the backend textures as mipmapped but, failing that, fall
434 // back to un-mipped.
Mike Reed13711eb2020-07-14 17:16:32 -0400435 std::unique_ptr<SkMipmap> mipmaps(SkMipmap::Build(tmp.pixmap(), nullptr));
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400436
437 newImageInfo.setMipLevels(tmp, std::move(mipmaps));
Robert Phillips96601082018-05-29 16:13:26 -0400438 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400439 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400440
441 return fImageInfo.count()-1;
442}
443
444int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
445 int preExistingID = this->findImage(image);
446 if (preExistingID >= 0) {
447 SkASSERT(this->isValidID(preExistingID));
448 return preExistingID;
449 }
450
451 int newID = this->addImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400452 return newID;
453}