blob: 931f03f3b716f1610d859810c7a120e8536cc8d7 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkCachedData.h"
Mike Reed13711eb2020-07-14 17:16:32 -040017#include "src/core/SkMipmap.h"
Robert Phillips923181b2020-02-14 12:36:37 -050018#include "src/core/SkTaskGroup.h"
19#include "src/gpu/GrContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/image/SkImage_Base.h"
21#include "src/image/SkImage_GpuYUVA.h"
Robert Phillips96601082018-05-29 16:13:26 -040022
Robert Phillipsf95e2f42020-04-17 16:20:55 -040023DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(int index,
24 uint32_t originalUniqueID,
25 const SkImageInfo& ii)
26 : fIndex(index)
27 , fOriginalUniqueID(originalUniqueID)
28 , fImageInfo(ii) {
29}
30
31DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(PromiseImageInfo&& other)
32 : fIndex(other.fIndex)
33 , fOriginalUniqueID(other.fOriginalUniqueID)
34 , fImageInfo(other.fImageInfo)
35 , fBaseLevel(other.fBaseLevel)
36 , fMipLevels(std::move(other.fMipLevels))
37 , fYUVData(std::move(other.fYUVData))
38 , fYUVColorSpace(other.fYUVColorSpace) {
39 memcpy(fYUVAIndices, other.fYUVAIndices, sizeof(fYUVAIndices));
40 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
41 fYUVPlanes[i] = other.fYUVPlanes[i];
42 fCallbackContexts[i] = std::move(other.fCallbackContexts[i]);
43 }
44}
45
46DDLPromiseImageHelper::PromiseImageInfo::~PromiseImageInfo() {}
47
48const std::unique_ptr<SkPixmap[]> DDLPromiseImageHelper::PromiseImageInfo::normalMipLevels() const {
49 SkASSERT(!this->isYUV());
50 std::unique_ptr<SkPixmap[]> pixmaps(new SkPixmap[this->numMipLevels()]);
51 pixmaps[0] = fBaseLevel.pixmap();
52 if (fMipLevels) {
53 for (int i = 0; i < fMipLevels->countLevels(); ++i) {
Mike Reed13711eb2020-07-14 17:16:32 -040054 SkMipmap::Level mipLevel;
Robert Phillipsf95e2f42020-04-17 16:20:55 -040055 fMipLevels->getLevel(i, &mipLevel);
56 pixmaps[i+1] = mipLevel.fPixmap;
57 }
58 }
59 return pixmaps;
60}
61
62int DDLPromiseImageHelper::PromiseImageInfo::numMipLevels() const {
63 SkASSERT(!this->isYUV());
64 return fMipLevels ? fMipLevels->countLevels()+1 : 1;
65}
66
67void DDLPromiseImageHelper::PromiseImageInfo::setMipLevels(const SkBitmap& baseLevel,
Mike Reed13711eb2020-07-14 17:16:32 -040068 std::unique_ptr<SkMipmap> mipLevels) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040069 fBaseLevel = baseLevel;
70 fMipLevels = std::move(mipLevels);
71}
72
73///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips11c67672020-04-23 15:10:03 -040074PromiseImageCallbackContext::~PromiseImageCallbackContext() {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050075 SkASSERT(fDoneCnt == fNumImages);
76 SkASSERT(!fUnreleasedFulfills);
77 SkASSERT(fTotalReleases == fTotalFulfills);
78 SkASSERT(!fTotalFulfills || fDoneCnt);
Robert Phillips96601082018-05-29 16:13:26 -040079
Brian Salomon3f4cd772019-01-11 16:03:19 -050080 if (fPromiseImageTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040081 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
Robert Phillips96601082018-05-29 16:13:26 -040082 }
83}
84
Robert Phillips11c67672020-04-23 15:10:03 -040085void PromiseImageCallbackContext::setBackendTexture(const GrBackendTexture& backendTexture) {
Brian Salomon7d88f312019-02-28 10:03:03 -050086 SkASSERT(!fPromiseImageTexture);
Robert Phillips923181b2020-02-14 12:36:37 -050087 SkASSERT(fBackendFormat == backendTexture.getBackendFormat());
Brian Salomon3f4cd772019-01-11 16:03:19 -050088 fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050089}
90
Robert Phillipsd5f3c982020-07-07 13:18:47 -040091void PromiseImageCallbackContext::destroyBackendTexture() {
92 SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
93
94 if (fPromiseImageTexture) {
95 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
96 }
97 fPromiseImageTexture = nullptr;
98}
99
Robert Phillips96601082018-05-29 16:13:26 -0400100///////////////////////////////////////////////////////////////////////////////////////////////////
101
102sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
103 SkSerialProcs procs;
104
105 procs.fImageCtx = this;
106 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
107 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
108
109 int id = helper->findOrDefineImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400110
Robert Phillips6bad7052019-12-16 15:09:57 -0500111 // Even if 'id' is invalid (i.e., -1) write it to the SKP
112 return SkData::MakeWithCopy(&id, sizeof(id));
Robert Phillips96601082018-05-29 16:13:26 -0400113 };
114
115 return inputPicture->serialize(&procs);
116}
117
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400118static GrBackendTexture create_yuva_texture(GrDirectContext* direct, const SkPixmap& pm,
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500119 const SkYUVAIndex yuvaIndices[4], int texIndex) {
120 SkASSERT(texIndex >= 0 && texIndex <= 3);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400121
122#ifdef SK_DEBUG
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500123 int channelCount = 0;
124 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
125 if (yuvaIndices[i].fIndex == texIndex) {
126 ++channelCount;
127 }
128 }
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500129 if (2 == channelCount) {
Robert Phillipsea1b30b2019-09-19 16:05:48 -0400130 SkASSERT(kR8G8_unorm_SkColorType == pm.colorType());
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500131 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400132#endif
Greg Danielc1ad77c2020-05-06 11:40:03 -0400133 bool finishedBECreate = false;
134 auto markFinished = [](void* context) {
135 *(bool*)context = true;
136 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400137 auto beTex = direct->createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo,
138 markFinished, &finishedBECreate);
Greg Danielc1ad77c2020-05-06 11:40:03 -0400139 if (beTex.isValid()) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400140 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400141 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400142 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400143 }
144 }
145 return beTex;
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500146}
147
Robert Phillips923181b2020-02-14 12:36:37 -0500148/*
149 * Create backend textures and upload data to them for all the textures required to satisfy
150 * a single promise image.
151 * For YUV textures this will result in up to 4 actual textures.
152 */
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400153void DDLPromiseImageHelper::CreateBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips923181b2020-02-14 12:36:37 -0500154 PromiseImageInfo* info) {
Robert Phillips923181b2020-02-14 12:36:37 -0500155 if (info->isYUV()) {
156 int numPixmaps;
157 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
158 for (int j = 0; j < numPixmaps; ++j) {
159 const SkPixmap& yuvPixmap = info->yuvPixmap(j);
160
161 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
162 SkASSERT(callbackContext);
163
Robert Phillips4508eb92020-04-15 15:54:34 -0400164 // DDL TODO: what should we do with mipmapped YUV images
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400165 callbackContext->setBackendTexture(create_yuva_texture(direct, yuvPixmap,
Robert Phillips923181b2020-02-14 12:36:37 -0500166 info->yuvaIndices(), j));
167 SkASSERT(callbackContext->promiseImageTexture());
168 }
169 } else {
170 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
171 if (!callbackContext) {
172 // This texture would've been too large to fit on the GPU
173 return;
174 }
175
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400176 std::unique_ptr<SkPixmap[]> mipLevels = info->normalMipLevels();
Robert Phillips923181b2020-02-14 12:36:37 -0500177
Greg Danielc1ad77c2020-05-06 11:40:03 -0400178 bool finishedBECreate = false;
179 auto markFinished = [](void* context) {
180 *(bool*)context = true;
181 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400182 auto backendTex = direct->createBackendTexture(mipLevels.get(), info->numMipLevels(),
183 GrRenderable::kNo, GrProtected::kNo,
184 markFinished, &finishedBECreate);
Robert Phillips923181b2020-02-14 12:36:37 -0500185 SkASSERT(backendTex.isValid());
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400186 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400187 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400188 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400189 }
Robert Phillips923181b2020-02-14 12:36:37 -0500190
191 callbackContext->setBackendTexture(backendTex);
192 }
193}
194
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400195void DDLPromiseImageHelper::DeleteBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips19f466d2020-02-26 10:27:07 -0500196 PromiseImageInfo* info) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500197 if (info->isYUV()) {
198 int numPixmaps;
199 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
200 for (int j = 0; j < numPixmaps; ++j) {
201 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
202 SkASSERT(callbackContext);
203
204 callbackContext->destroyBackendTexture();
205 SkASSERT(!callbackContext->promiseImageTexture());
206 }
207 } else {
208 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
209 if (!callbackContext) {
210 // This texture would've been too large to fit on the GPU
211 return;
212 }
213
214 callbackContext->destroyBackendTexture();
215 SkASSERT(!callbackContext->promiseImageTexture());
216 }
217}
218
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400219void DDLPromiseImageHelper::createCallbackContexts(GrDirectContext* direct) {
220 const GrCaps* caps = direct->priv().caps();
Robert Phillips923181b2020-02-14 12:36:37 -0500221 const int maxDimension = caps->maxTextureSize();
222
223 for (int i = 0; i < fImageInfo.count(); ++i) {
224 PromiseImageInfo& info = fImageInfo[i];
225
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400226 if (info.isYUV()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400227 int numPixmaps;
228 SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
Robert Phillips923181b2020-02-14 12:36:37 -0500229
Jim Van Verth8f11e432018-10-18 14:36:59 -0400230 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400231 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -0400232
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400233 GrBackendFormat backendFormat = direct->defaultBackendFormat(yuvPixmap.colorType(),
234 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500235
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400236 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400237 new PromiseImageCallbackContext(direct, backendFormat));
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500238
Robert Phillips923181b2020-02-14 12:36:37 -0500239 info.setCallbackContext(j, std::move(callbackContext));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400240 }
241 } else {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400242 const SkBitmap& baseLevel = info.baseLevel();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400243
Robert Phillips923181b2020-02-14 12:36:37 -0500244 // TODO: explicitly mark the PromiseImageInfo as too big and check in uploadAllToGPU
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400245 if (maxDimension < std::max(baseLevel.width(), baseLevel.height())) {
Robert Phillips923181b2020-02-14 12:36:37 -0500246 // This won't fit on the GPU. Fallback to a raster-backed image per tile.
247 continue;
248 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400249
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400250 GrBackendFormat backendFormat = direct->defaultBackendFormat(baseLevel.colorType(),
251 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500252 if (!caps->isFormatTexturable(backendFormat)) {
253 continue;
254 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400255
Robert Phillips923181b2020-02-14 12:36:37 -0500256 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400257 new PromiseImageCallbackContext(direct, backendFormat));
Robert Phillips923181b2020-02-14 12:36:37 -0500258
259 info.setCallbackContext(0, std::move(callbackContext));
260 }
261 }
262}
263
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400264void DDLPromiseImageHelper::uploadAllToGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips923181b2020-02-14 12:36:37 -0500265 if (taskGroup) {
266 for (int i = 0; i < fImageInfo.count(); ++i) {
267 PromiseImageInfo* info = &fImageInfo[i];
268
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400269 taskGroup->add([direct, info]() { CreateBETexturesForPromiseImage(direct, info); });
Robert Phillips923181b2020-02-14 12:36:37 -0500270 }
271 } else {
272 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400273 CreateBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400274 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500275 }
276}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400277
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400278void DDLPromiseImageHelper::deleteAllFromGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500279 if (taskGroup) {
280 for (int i = 0; i < fImageInfo.count(); ++i) {
281 PromiseImageInfo* info = &fImageInfo[i];
282
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400283 taskGroup->add([direct, info]() { DeleteBETexturesForPromiseImage(direct, info); });
Robert Phillips19f466d2020-02-26 10:27:07 -0500284 }
285 } else {
286 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400287 DeleteBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillips19f466d2020-02-26 10:27:07 -0500288 }
289 }
290}
291
Robert Phillips96601082018-05-29 16:13:26 -0400292sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
293 SkDeferredDisplayListRecorder* recorder,
294 SkData* compressedPictureData,
295 SkTArray<sk_sp<SkImage>>* promiseImages) const {
296 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
297
298 SkDeserialProcs procs;
299 procs.fImageCtx = (void*) &perRecorderContext;
Robert Phillips923181b2020-02-14 12:36:37 -0500300 procs.fImageProc = CreatePromiseImages;
Robert Phillips96601082018-05-29 16:13:26 -0400301
302 return SkPicture::MakeFromData(compressedPictureData, &procs);
303}
304
305// This generates promise images to replace the indices in the compressed picture. This
306// reconstitution is performed separately in each thread so we end up with multiple
307// promise images referring to the same GrBackendTexture.
Robert Phillips923181b2020-02-14 12:36:37 -0500308sk_sp<SkImage> DDLPromiseImageHelper::CreatePromiseImages(const void* rawData,
Robert Phillips96601082018-05-29 16:13:26 -0400309 size_t length, void* ctxIn) {
310 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
311 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
312 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
313
314 SkASSERT(length == sizeof(int));
315
316 const int* indexPtr = static_cast<const int*>(rawData);
Robert Phillips6bad7052019-12-16 15:09:57 -0500317 if (!helper->isValidID(*indexPtr)) {
318 return nullptr;
319 }
Robert Phillips96601082018-05-29 16:13:26 -0400320
321 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
322
Robert Phillips923181b2020-02-14 12:36:37 -0500323 // If there is no callback context that means 'createCallbackContexts' determined the
324 // texture wouldn't fit on the GPU. Create a separate bitmap-backed image for each thread.
325 if (!curImage.isYUV() && !curImage.callbackContext(0)) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400326 SkASSERT(curImage.baseLevel().isImmutable());
327 return SkImage::MakeFromBitmap(curImage.baseLevel());
Robert Phillips96601082018-05-29 16:13:26 -0400328 }
Robert Phillips923181b2020-02-14 12:36:37 -0500329
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400330 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400331
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400332 sk_sp<SkImage> image;
333 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400334 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
335 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
336 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400337 // TODO: store this value somewhere?
338 int textureCount;
339 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
340 for (int i = 0; i < textureCount; ++i) {
Robert Phillips923181b2020-02-14 12:36:37 -0500341 backendFormats[i] = curImage.backendFormat(i);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500342 SkASSERT(backendFormats[i].isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400343 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400344 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400345 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400346 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400347 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400348 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000349
Brian Salomon0cc57542019-03-08 13:28:46 -0500350 image = recorder->makeYUVAPromiseTexture(
351 curImage.yuvColorSpace(),
352 backendFormats,
353 sizes,
354 curImage.yuvaIndices(),
355 curImage.overallWidth(),
356 curImage.overallHeight(),
357 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
358 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400359 PromiseImageCallbackContext::PromiseImageFulfillProc,
360 PromiseImageCallbackContext::PromiseImageReleaseProc,
361 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500362 contexts,
363 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500364 for (int i = 0; i < textureCount; ++i) {
365 curImage.callbackContext(i)->wasAddedToImage();
366 }
Robert Phillips193c4212019-03-04 12:18:53 -0500367
368#ifdef SK_DEBUG
369 {
370 // By the peekProxy contract this image should not have a single backing proxy so
371 // should return null. The call should also not trigger the conversion to RGBA.
372 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
373 SkASSERT(!yuva->peekProxy());
374 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
375 }
376#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400377 } else {
Robert Phillips923181b2020-02-14 12:36:37 -0500378 GrBackendFormat backendFormat = curImage.backendFormat(0);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500379 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400380
381 // Each DDL recorder gets its own ref on the promise callback context for the
382 // promise images it creates.
Brian Salomon0cc57542019-03-08 13:28:46 -0500383 image = recorder->makePromiseTexture(
384 backendFormat,
385 curImage.overallWidth(),
386 curImage.overallHeight(),
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400387 curImage.mipMapped(0),
Brian Salomon0cc57542019-03-08 13:28:46 -0500388 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
389 curImage.overallColorType(),
390 curImage.overallAlphaType(),
391 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400392 PromiseImageCallbackContext::PromiseImageFulfillProc,
393 PromiseImageCallbackContext::PromiseImageReleaseProc,
394 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500395 (void*)curImage.refCallbackContext(0).release(),
396 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500397 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400398 }
Robert Phillips96601082018-05-29 16:13:26 -0400399 perRecorderContext->fPromiseImages->push_back(image);
400 SkASSERT(image);
401 return image;
402}
403
404int DDLPromiseImageHelper::findImage(SkImage* image) const {
405 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400406 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
407 SkASSERT(fImageInfo[i].index() == i);
408 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400409 return i;
410 }
411 }
412 return -1;
413}
414
415int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400416 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400417
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400418 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400419 image->colorType() == kBGRA_8888_SkColorType
420 ? kRGBA_8888_SkColorType
421 : image->colorType(),
422 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400423 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400424
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400425 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
426 image->uniqueID(),
427 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400428
Jim Van Verthe24b5872018-10-29 16:26:02 -0400429 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400430 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400431 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400432 const void* planes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400433 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400434 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400435 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400436
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400437 // determine colortypes from index data
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400438 // for testing we only ever use A8, RG_88
Jim Van Verthe24b5872018-10-29 16:26:02 -0400439 SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400440 kUnknown_SkColorType, kUnknown_SkColorType,
441 kUnknown_SkColorType, kUnknown_SkColorType
442 };
443 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
444 int texIdx = yuvaIndices[yuvIndex].fIndex;
445 if (texIdx < 0) {
446 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
447 continue;
448 }
449 if (kUnknown_SkColorType == colorTypes[texIdx]) {
450 colorTypes[texIdx] = kAlpha_8_SkColorType;
451 } else {
Robert Phillipsea1b30b2019-09-19 16:05:48 -0400452 colorTypes[texIdx] = kR8G8_unorm_SkColorType;
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400453 }
454 }
455
Jim Van Verthe24b5872018-10-29 16:26:02 -0400456 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400457 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
458 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400459 continue;
460 }
461
462 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
463 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400464 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400465 kUnpremul_SkAlphaType);
466 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400467 }
468 } else {
469 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
Robert Phillipse84bffc2019-12-16 11:22:17 -0500470 if (!rasterImage) {
471 return -1;
472 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400473
474 SkBitmap tmp;
475 tmp.allocPixels(overallII);
476
477 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
478 return -1;
479 }
480
481 tmp.setImmutable();
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400482
483 // Given how the DDL testing harness works (i.e., only modifying the SkImages w/in an
484 // SKP) we don't know if a given SkImage will require mipmapping. To work around this
485 // we just try to create all the backend textures as mipmapped but, failing that, fall
486 // back to un-mipped.
Mike Reed13711eb2020-07-14 17:16:32 -0400487 std::unique_ptr<SkMipmap> mipmaps(SkMipmap::Build(tmp.pixmap(), nullptr));
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400488
489 newImageInfo.setMipLevels(tmp, std::move(mipmaps));
Robert Phillips96601082018-05-29 16:13:26 -0400490 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400491 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400492
493 return fImageInfo.count()-1;
494}
495
496int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
497 int preExistingID = this->findImage(image);
498 if (preExistingID >= 0) {
499 SkASSERT(this->isValidID(preExistingID));
500 return preExistingID;
501 }
502
503 int newID = this->addImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400504 return newID;
505}