blob: 0ae1df7e87223d64f9ba480968a5d847fe2e3bdd [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 Salomonefb5f072020-07-28 21:06:43 -040016#include "src/codec/SkCodecImageGenerator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkCachedData.h"
Mike Reed13711eb2020-07-14 17:16:32 -040018#include "src/core/SkMipmap.h"
Robert Phillips923181b2020-02-14 12:36:37 -050019#include "src/core/SkTaskGroup.h"
20#include "src/gpu/GrContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/image/SkImage_Base.h"
22#include "src/image/SkImage_GpuYUVA.h"
Robert Phillips96601082018-05-29 16:13:26 -040023
Robert Phillipsf95e2f42020-04-17 16:20:55 -040024DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(int index,
25 uint32_t originalUniqueID,
26 const SkImageInfo& ii)
27 : fIndex(index)
28 , fOriginalUniqueID(originalUniqueID)
29 , fImageInfo(ii) {
30}
31
32DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(PromiseImageInfo&& other)
33 : fIndex(other.fIndex)
34 , fOriginalUniqueID(other.fOriginalUniqueID)
35 , fImageInfo(other.fImageInfo)
36 , fBaseLevel(other.fBaseLevel)
37 , fMipLevels(std::move(other.fMipLevels))
Robert Phillipsf95e2f42020-04-17 16:20:55 -040038 , fYUVColorSpace(other.fYUVColorSpace) {
39 memcpy(fYUVAIndices, other.fYUVAIndices, sizeof(fYUVAIndices));
40 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Brian Salomonefb5f072020-07-28 21:06:43 -040041 fYUVPlanes[i] = std::move(other.fYUVPlanes[i]);
Robert Phillipsf95e2f42020-04-17 16:20:55 -040042 fCallbackContexts[i] = std::move(other.fCallbackContexts[i]);
43 }
44}
45
46DDLPromiseImageHelper::PromiseImageInfo::~PromiseImageInfo() {}
47
John Stilesec9b4aa2020-08-07 13:05:14 -040048std::unique_ptr<SkPixmap[]> DDLPromiseImageHelper::PromiseImageInfo::normalMipLevels() const {
Robert Phillipsf95e2f42020-04-17 16:20:55 -040049 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
Brian Salomonefb5f072020-07-28 21:06:43 -040073void DDLPromiseImageHelper::PromiseImageInfo::setYUVPlanes(
74 const SkYUVASizeInfo& yuvaSizeInfo,
75 const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
76 SkYUVColorSpace cs,
77 std::unique_ptr<char[]> planes[SkYUVAIndex::kIndexCount]) {
78 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
79 fYUVColorSpace = cs;
80 SkColorType colorTypes[] = {kUnknown_SkColorType,
81 kUnknown_SkColorType,
82 kUnknown_SkColorType,
83 kUnknown_SkColorType};
84 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
85 int texIdx = yuvaIndices[yuvIndex].fIndex;
86 if (texIdx < 0) {
87 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
88 continue;
89 }
90 // In current testing only ever expect A8, RG_88
91 if (colorTypes[texIdx] == kUnknown_SkColorType) {
92 colorTypes[texIdx] = kAlpha_8_SkColorType;
93 } else {
94 SkASSERT(colorTypes[texIdx] == kAlpha_8_SkColorType);
95 colorTypes[texIdx] = kR8G8_unorm_SkColorType;
96 }
97 }
98
99 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
100 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
101 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && colorTypes[i] == kUnknown_SkColorType);
102 continue;
103 }
104 auto info = SkImageInfo::Make(yuvaSizeInfo.fSizes[i], colorTypes[i], kPremul_SkAlphaType);
105 auto release = [](void* addr, void*) { std::unique_ptr<char[]>(static_cast<char*>(addr)); };
Robert Phillips15543682020-08-06 14:30:46 -0400106 char* pixels = planes[i].release();
107 fYUVPlanes[i].installPixels(info, pixels, yuvaSizeInfo.fWidthBytes[i], release, pixels);
Brian Salomonefb5f072020-07-28 21:06:43 -0400108 }
109}
110
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400111///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips11c67672020-04-23 15:10:03 -0400112PromiseImageCallbackContext::~PromiseImageCallbackContext() {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500113 SkASSERT(fDoneCnt == fNumImages);
114 SkASSERT(!fUnreleasedFulfills);
115 SkASSERT(fTotalReleases == fTotalFulfills);
116 SkASSERT(!fTotalFulfills || fDoneCnt);
Robert Phillips96601082018-05-29 16:13:26 -0400117
Brian Salomon3f4cd772019-01-11 16:03:19 -0500118 if (fPromiseImageTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400119 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
Robert Phillips96601082018-05-29 16:13:26 -0400120 }
121}
122
Robert Phillips11c67672020-04-23 15:10:03 -0400123void PromiseImageCallbackContext::setBackendTexture(const GrBackendTexture& backendTexture) {
Brian Salomon7d88f312019-02-28 10:03:03 -0500124 SkASSERT(!fPromiseImageTexture);
Robert Phillips923181b2020-02-14 12:36:37 -0500125 SkASSERT(fBackendFormat == backendTexture.getBackendFormat());
Brian Salomon3f4cd772019-01-11 16:03:19 -0500126 fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500127}
128
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400129void PromiseImageCallbackContext::destroyBackendTexture() {
130 SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
131
132 if (fPromiseImageTexture) {
133 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
134 }
135 fPromiseImageTexture = nullptr;
136}
137
Robert Phillips96601082018-05-29 16:13:26 -0400138///////////////////////////////////////////////////////////////////////////////////////////////////
139
140sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
141 SkSerialProcs procs;
142
143 procs.fImageCtx = this;
144 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
145 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
146
147 int id = helper->findOrDefineImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400148
Robert Phillips6bad7052019-12-16 15:09:57 -0500149 // Even if 'id' is invalid (i.e., -1) write it to the SKP
150 return SkData::MakeWithCopy(&id, sizeof(id));
Robert Phillips96601082018-05-29 16:13:26 -0400151 };
152
153 return inputPicture->serialize(&procs);
154}
155
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400156static GrBackendTexture create_yuva_texture(GrDirectContext* direct, const SkPixmap& pm,
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500157 const SkYUVAIndex yuvaIndices[4], int texIndex) {
158 SkASSERT(texIndex >= 0 && texIndex <= 3);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400159
160#ifdef SK_DEBUG
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500161 int channelCount = 0;
162 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
163 if (yuvaIndices[i].fIndex == texIndex) {
164 ++channelCount;
165 }
166 }
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500167 if (2 == channelCount) {
Robert Phillipsea1b30b2019-09-19 16:05:48 -0400168 SkASSERT(kR8G8_unorm_SkColorType == pm.colorType());
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500169 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400170#endif
Greg Danielc1ad77c2020-05-06 11:40:03 -0400171 bool finishedBECreate = false;
172 auto markFinished = [](void* context) {
173 *(bool*)context = true;
174 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400175 auto beTex = direct->createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo,
176 markFinished, &finishedBECreate);
Greg Danielc1ad77c2020-05-06 11:40:03 -0400177 if (beTex.isValid()) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400178 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400179 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400180 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400181 }
182 }
183 return beTex;
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500184}
185
Robert Phillips923181b2020-02-14 12:36:37 -0500186/*
187 * Create backend textures and upload data to them for all the textures required to satisfy
188 * a single promise image.
189 * For YUV textures this will result in up to 4 actual textures.
190 */
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400191void DDLPromiseImageHelper::CreateBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips923181b2020-02-14 12:36:37 -0500192 PromiseImageInfo* info) {
Robert Phillips923181b2020-02-14 12:36:37 -0500193 if (info->isYUV()) {
194 int numPixmaps;
195 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
196 for (int j = 0; j < numPixmaps; ++j) {
197 const SkPixmap& yuvPixmap = info->yuvPixmap(j);
198
199 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
200 SkASSERT(callbackContext);
201
Robert Phillips4508eb92020-04-15 15:54:34 -0400202 // DDL TODO: what should we do with mipmapped YUV images
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400203 callbackContext->setBackendTexture(create_yuva_texture(direct, yuvPixmap,
Robert Phillips923181b2020-02-14 12:36:37 -0500204 info->yuvaIndices(), j));
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
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400214 std::unique_ptr<SkPixmap[]> mipLevels = info->normalMipLevels();
Robert Phillips923181b2020-02-14 12:36:37 -0500215
Greg Danielc1ad77c2020-05-06 11:40:03 -0400216 bool finishedBECreate = false;
217 auto markFinished = [](void* context) {
218 *(bool*)context = true;
219 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400220 auto backendTex = direct->createBackendTexture(mipLevels.get(), info->numMipLevels(),
221 GrRenderable::kNo, GrProtected::kNo,
222 markFinished, &finishedBECreate);
Robert Phillips923181b2020-02-14 12:36:37 -0500223 SkASSERT(backendTex.isValid());
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400224 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400225 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400226 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400227 }
Robert Phillips923181b2020-02-14 12:36:37 -0500228
229 callbackContext->setBackendTexture(backendTex);
230 }
231}
232
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400233void DDLPromiseImageHelper::DeleteBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips19f466d2020-02-26 10:27:07 -0500234 PromiseImageInfo* info) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500235 if (info->isYUV()) {
236 int numPixmaps;
237 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
238 for (int j = 0; j < numPixmaps; ++j) {
239 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
240 SkASSERT(callbackContext);
241
242 callbackContext->destroyBackendTexture();
243 SkASSERT(!callbackContext->promiseImageTexture());
244 }
245 } else {
246 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
247 if (!callbackContext) {
248 // This texture would've been too large to fit on the GPU
249 return;
250 }
251
252 callbackContext->destroyBackendTexture();
253 SkASSERT(!callbackContext->promiseImageTexture());
254 }
255}
256
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400257void DDLPromiseImageHelper::createCallbackContexts(GrDirectContext* direct) {
258 const GrCaps* caps = direct->priv().caps();
Robert Phillips923181b2020-02-14 12:36:37 -0500259 const int maxDimension = caps->maxTextureSize();
260
261 for (int i = 0; i < fImageInfo.count(); ++i) {
262 PromiseImageInfo& info = fImageInfo[i];
263
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400264 if (info.isYUV()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400265 int numPixmaps;
266 SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
Robert Phillips923181b2020-02-14 12:36:37 -0500267
Jim Van Verth8f11e432018-10-18 14:36:59 -0400268 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400269 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -0400270
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400271 GrBackendFormat backendFormat = direct->defaultBackendFormat(yuvPixmap.colorType(),
272 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500273
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400274 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400275 new PromiseImageCallbackContext(direct, backendFormat));
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500276
Robert Phillips923181b2020-02-14 12:36:37 -0500277 info.setCallbackContext(j, std::move(callbackContext));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400278 }
279 } else {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400280 const SkBitmap& baseLevel = info.baseLevel();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400281
Robert Phillips923181b2020-02-14 12:36:37 -0500282 // TODO: explicitly mark the PromiseImageInfo as too big and check in uploadAllToGPU
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400283 if (maxDimension < std::max(baseLevel.width(), baseLevel.height())) {
Robert Phillips923181b2020-02-14 12:36:37 -0500284 // This won't fit on the GPU. Fallback to a raster-backed image per tile.
285 continue;
286 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400287
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400288 GrBackendFormat backendFormat = direct->defaultBackendFormat(baseLevel.colorType(),
289 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500290 if (!caps->isFormatTexturable(backendFormat)) {
291 continue;
292 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400293
Robert Phillips923181b2020-02-14 12:36:37 -0500294 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400295 new PromiseImageCallbackContext(direct, backendFormat));
Robert Phillips923181b2020-02-14 12:36:37 -0500296
297 info.setCallbackContext(0, std::move(callbackContext));
298 }
299 }
300}
301
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400302void DDLPromiseImageHelper::uploadAllToGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips923181b2020-02-14 12:36:37 -0500303 if (taskGroup) {
304 for (int i = 0; i < fImageInfo.count(); ++i) {
305 PromiseImageInfo* info = &fImageInfo[i];
306
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400307 taskGroup->add([direct, info]() { CreateBETexturesForPromiseImage(direct, info); });
Robert Phillips923181b2020-02-14 12:36:37 -0500308 }
309 } else {
310 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400311 CreateBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400312 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500313 }
314}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400315
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400316void DDLPromiseImageHelper::deleteAllFromGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500317 if (taskGroup) {
318 for (int i = 0; i < fImageInfo.count(); ++i) {
319 PromiseImageInfo* info = &fImageInfo[i];
320
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400321 taskGroup->add([direct, info]() { DeleteBETexturesForPromiseImage(direct, info); });
Robert Phillips19f466d2020-02-26 10:27:07 -0500322 }
323 } else {
324 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400325 DeleteBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillips19f466d2020-02-26 10:27:07 -0500326 }
327 }
328}
329
Robert Phillips96601082018-05-29 16:13:26 -0400330sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
331 SkDeferredDisplayListRecorder* recorder,
332 SkData* compressedPictureData,
333 SkTArray<sk_sp<SkImage>>* promiseImages) const {
334 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
335
336 SkDeserialProcs procs;
337 procs.fImageCtx = (void*) &perRecorderContext;
Robert Phillips923181b2020-02-14 12:36:37 -0500338 procs.fImageProc = CreatePromiseImages;
Robert Phillips96601082018-05-29 16:13:26 -0400339
340 return SkPicture::MakeFromData(compressedPictureData, &procs);
341}
342
343// This generates promise images to replace the indices in the compressed picture. This
344// reconstitution is performed separately in each thread so we end up with multiple
345// promise images referring to the same GrBackendTexture.
Robert Phillips923181b2020-02-14 12:36:37 -0500346sk_sp<SkImage> DDLPromiseImageHelper::CreatePromiseImages(const void* rawData,
Robert Phillips96601082018-05-29 16:13:26 -0400347 size_t length, void* ctxIn) {
348 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
349 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
350 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
351
352 SkASSERT(length == sizeof(int));
353
354 const int* indexPtr = static_cast<const int*>(rawData);
Robert Phillips6bad7052019-12-16 15:09:57 -0500355 if (!helper->isValidID(*indexPtr)) {
356 return nullptr;
357 }
Robert Phillips96601082018-05-29 16:13:26 -0400358
359 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
360
Robert Phillips923181b2020-02-14 12:36:37 -0500361 // If there is no callback context that means 'createCallbackContexts' determined the
362 // texture wouldn't fit on the GPU. Create a separate bitmap-backed image for each thread.
363 if (!curImage.isYUV() && !curImage.callbackContext(0)) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400364 SkASSERT(curImage.baseLevel().isImmutable());
365 return SkImage::MakeFromBitmap(curImage.baseLevel());
Robert Phillips96601082018-05-29 16:13:26 -0400366 }
Robert Phillips923181b2020-02-14 12:36:37 -0500367
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400368 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400369
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400370 sk_sp<SkImage> image;
371 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400372 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
373 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
374 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400375 // TODO: store this value somewhere?
376 int textureCount;
377 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
378 for (int i = 0; i < textureCount; ++i) {
Robert Phillips923181b2020-02-14 12:36:37 -0500379 backendFormats[i] = curImage.backendFormat(i);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500380 SkASSERT(backendFormats[i].isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400381 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400382 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400383 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400384 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400385 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400386 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000387
Brian Salomon0cc57542019-03-08 13:28:46 -0500388 image = recorder->makeYUVAPromiseTexture(
389 curImage.yuvColorSpace(),
390 backendFormats,
391 sizes,
392 curImage.yuvaIndices(),
393 curImage.overallWidth(),
394 curImage.overallHeight(),
395 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
396 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400397 PromiseImageCallbackContext::PromiseImageFulfillProc,
398 PromiseImageCallbackContext::PromiseImageReleaseProc,
399 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500400 contexts,
401 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500402 for (int i = 0; i < textureCount; ++i) {
403 curImage.callbackContext(i)->wasAddedToImage();
404 }
Robert Phillips193c4212019-03-04 12:18:53 -0500405
406#ifdef SK_DEBUG
407 {
408 // By the peekProxy contract this image should not have a single backing proxy so
409 // should return null. The call should also not trigger the conversion to RGBA.
410 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
411 SkASSERT(!yuva->peekProxy());
412 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
413 }
414#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400415 } else {
Robert Phillips923181b2020-02-14 12:36:37 -0500416 GrBackendFormat backendFormat = curImage.backendFormat(0);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500417 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400418
419 // Each DDL recorder gets its own ref on the promise callback context for the
420 // promise images it creates.
Brian Salomon0cc57542019-03-08 13:28:46 -0500421 image = recorder->makePromiseTexture(
422 backendFormat,
423 curImage.overallWidth(),
424 curImage.overallHeight(),
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400425 curImage.mipMapped(0),
Brian Salomon0cc57542019-03-08 13:28:46 -0500426 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
427 curImage.overallColorType(),
428 curImage.overallAlphaType(),
429 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400430 PromiseImageCallbackContext::PromiseImageFulfillProc,
431 PromiseImageCallbackContext::PromiseImageReleaseProc,
432 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500433 (void*)curImage.refCallbackContext(0).release(),
434 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500435 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400436 }
Robert Phillips96601082018-05-29 16:13:26 -0400437 perRecorderContext->fPromiseImages->push_back(image);
438 SkASSERT(image);
439 return image;
440}
441
442int DDLPromiseImageHelper::findImage(SkImage* image) const {
443 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400444 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
445 SkASSERT(fImageInfo[i].index() == i);
446 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400447 return i;
448 }
449 }
450 return -1;
451}
452
453int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400454 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400455
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400456 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400457 image->colorType() == kBGRA_8888_SkColorType
458 ? kRGBA_8888_SkColorType
459 : image->colorType(),
460 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400461 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400462
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400463 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
464 image->uniqueID(),
465 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400466
Jim Van Verthe24b5872018-10-29 16:26:02 -0400467 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400468 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400469 SkYUVColorSpace yuvColorSpace;
Brian Salomonefb5f072020-07-28 21:06:43 -0400470 auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(ib->refEncodedData());
471 std::unique_ptr<char[]> planes[SkYUVASizeInfo::kMaxCount];
472 if (codec && codec->queryYUVA8(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace)) {
473 void* data[4];
474 for (int i = 0; i < 4; ++i) {
475 size_t size = yuvaSizeInfo.fSizes[i].height() * yuvaSizeInfo.fWidthBytes[i];
476 if (size) {
477 planes[i].reset(new char[size]);
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400478 }
Brian Salomonefb5f072020-07-28 21:06:43 -0400479 data[i] = planes[i].get();
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400480 }
Brian Salomonefb5f072020-07-28 21:06:43 -0400481 SkAssertResult(codec->getYUVA8Planes(yuvaSizeInfo, yuvaIndices, data));
482 newImageInfo.setYUVPlanes(yuvaSizeInfo, yuvaIndices, yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400483 } else {
484 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
Robert Phillipse84bffc2019-12-16 11:22:17 -0500485 if (!rasterImage) {
486 return -1;
487 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400488
489 SkBitmap tmp;
490 tmp.allocPixels(overallII);
491
492 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
493 return -1;
494 }
495
496 tmp.setImmutable();
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400497
498 // Given how the DDL testing harness works (i.e., only modifying the SkImages w/in an
499 // SKP) we don't know if a given SkImage will require mipmapping. To work around this
500 // we just try to create all the backend textures as mipmapped but, failing that, fall
501 // back to un-mipped.
Mike Reed13711eb2020-07-14 17:16:32 -0400502 std::unique_ptr<SkMipmap> mipmaps(SkMipmap::Build(tmp.pixmap(), nullptr));
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400503
504 newImageInfo.setMipLevels(tmp, std::move(mipmaps));
Robert Phillips96601082018-05-29 16:13:26 -0400505 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400506 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400507
508 return fImageInfo.count()-1;
509}
510
511int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
512 int preExistingID = this->findImage(image);
513 if (preExistingID >= 0) {
514 SkASSERT(this->isValidID(preExistingID));
515 return preExistingID;
516 }
517
518 int newID = this->addImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400519 return newID;
520}