blob: 2af072f861b8eef2cce12b2f126bb1bebee1fb27 [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"
Brian Salomon5660e8b2020-08-25 12:40:32 -040020#include "src/core/SkYUVAInfoPriv.h"
Robert Phillips923181b2020-02-14 12:36:37 -050021#include "src/gpu/GrContextPriv.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 }
Brian Salomon5660e8b2020-08-25 12:40:32 -040043 std::copy_n(other.fYUVAIndices, SkYUVAIndex::kIndexCount, fYUVAIndices);
Robert Phillipsf95e2f42020-04-17 16:20:55 -040044}
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 Salomon5660e8b2020-08-25 12:40:32 -040073void DDLPromiseImageHelper::PromiseImageInfo::initYUVAIndices() {
74 SkYUVASizeInfo unusedSizeInfo;
75 SkYUVAInfoPriv::InitLegacyInfo(fYUVAPixmaps.yuvaInfo(), fYUVAPixmaps.planes(), &unusedSizeInfo,
76 fYUVAIndices);
77 // We can wind up with alpha pixmaps that become red textures. If so, update YUVA indices.
78 // Note: This goes away when we start creating YUVA images using SkYUVAInfo.
79 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
80 if (fYUVAIndices[i].fIndex >= 0) {
81 int textureIdx = fYUVAIndices[i].fIndex;
82 const auto& format = fCallbackContexts[textureIdx]->backendFormat();
83 if (fYUVAIndices[i].fChannel == SkColorChannel::kA &&
84 format.channelMask() == SkColorChannelFlag::kRed_SkColorChannelFlag) {
85 fYUVAIndices[i].fChannel = SkColorChannel::kR;
86 }
Brian Salomonefb5f072020-07-28 21:06:43 -040087 }
Brian Salomonefb5f072020-07-28 21:06:43 -040088 }
89}
90
Robert Phillipsf95e2f42020-04-17 16:20:55 -040091///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips11c67672020-04-23 15:10:03 -040092PromiseImageCallbackContext::~PromiseImageCallbackContext() {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050093 SkASSERT(fDoneCnt == fNumImages);
94 SkASSERT(!fUnreleasedFulfills);
95 SkASSERT(fTotalReleases == fTotalFulfills);
96 SkASSERT(!fTotalFulfills || fDoneCnt);
Robert Phillips96601082018-05-29 16:13:26 -040097
Brian Salomon3f4cd772019-01-11 16:03:19 -050098 if (fPromiseImageTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040099 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
Robert Phillips96601082018-05-29 16:13:26 -0400100 }
101}
102
Robert Phillips11c67672020-04-23 15:10:03 -0400103void PromiseImageCallbackContext::setBackendTexture(const GrBackendTexture& backendTexture) {
Brian Salomon7d88f312019-02-28 10:03:03 -0500104 SkASSERT(!fPromiseImageTexture);
Robert Phillips923181b2020-02-14 12:36:37 -0500105 SkASSERT(fBackendFormat == backendTexture.getBackendFormat());
Brian Salomon3f4cd772019-01-11 16:03:19 -0500106 fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500107}
108
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400109void PromiseImageCallbackContext::destroyBackendTexture() {
110 SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
111
112 if (fPromiseImageTexture) {
113 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
114 }
115 fPromiseImageTexture = nullptr;
116}
117
Robert Phillips96601082018-05-29 16:13:26 -0400118///////////////////////////////////////////////////////////////////////////////////////////////////
119
120sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
121 SkSerialProcs procs;
122
123 procs.fImageCtx = this;
124 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
125 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
126
127 int id = helper->findOrDefineImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400128
Robert Phillips6bad7052019-12-16 15:09:57 -0500129 // Even if 'id' is invalid (i.e., -1) write it to the SKP
130 return SkData::MakeWithCopy(&id, sizeof(id));
Robert Phillips96601082018-05-29 16:13:26 -0400131 };
132
133 return inputPicture->serialize(&procs);
134}
135
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400136static GrBackendTexture create_yuva_texture(GrDirectContext* direct, const SkPixmap& pm,
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500137 const SkYUVAIndex yuvaIndices[4], int texIndex) {
138 SkASSERT(texIndex >= 0 && texIndex <= 3);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400139
140#ifdef SK_DEBUG
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500141 int channelCount = 0;
142 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
143 if (yuvaIndices[i].fIndex == texIndex) {
144 ++channelCount;
145 }
146 }
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500147 if (2 == channelCount) {
Robert Phillipsea1b30b2019-09-19 16:05:48 -0400148 SkASSERT(kR8G8_unorm_SkColorType == pm.colorType());
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500149 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400150#endif
Greg Danielc1ad77c2020-05-06 11:40:03 -0400151 bool finishedBECreate = false;
152 auto markFinished = [](void* context) {
153 *(bool*)context = true;
154 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400155 auto beTex = direct->createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo,
156 markFinished, &finishedBECreate);
Greg Danielc1ad77c2020-05-06 11:40:03 -0400157 if (beTex.isValid()) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400158 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400159 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400160 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400161 }
162 }
163 return beTex;
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500164}
165
Robert Phillips923181b2020-02-14 12:36:37 -0500166/*
167 * Create backend textures and upload data to them for all the textures required to satisfy
168 * a single promise image.
169 * For YUV textures this will result in up to 4 actual textures.
170 */
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400171void DDLPromiseImageHelper::CreateBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips923181b2020-02-14 12:36:37 -0500172 PromiseImageInfo* info) {
Robert Phillips923181b2020-02-14 12:36:37 -0500173 if (info->isYUV()) {
174 int numPixmaps;
175 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
176 for (int j = 0; j < numPixmaps; ++j) {
177 const SkPixmap& yuvPixmap = info->yuvPixmap(j);
178
179 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
180 SkASSERT(callbackContext);
181
Robert Phillips4508eb92020-04-15 15:54:34 -0400182 // DDL TODO: what should we do with mipmapped YUV images
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400183 callbackContext->setBackendTexture(create_yuva_texture(direct, yuvPixmap,
Robert Phillips923181b2020-02-14 12:36:37 -0500184 info->yuvaIndices(), j));
185 SkASSERT(callbackContext->promiseImageTexture());
186 }
187 } else {
188 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
189 if (!callbackContext) {
190 // This texture would've been too large to fit on the GPU
191 return;
192 }
193
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400194 std::unique_ptr<SkPixmap[]> mipLevels = info->normalMipLevels();
Robert Phillips923181b2020-02-14 12:36:37 -0500195
Greg Danielc1ad77c2020-05-06 11:40:03 -0400196 bool finishedBECreate = false;
197 auto markFinished = [](void* context) {
198 *(bool*)context = true;
199 };
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400200 auto backendTex = direct->createBackendTexture(mipLevels.get(), info->numMipLevels(),
201 GrRenderable::kNo, GrProtected::kNo,
202 markFinished, &finishedBECreate);
Robert Phillips923181b2020-02-14 12:36:37 -0500203 SkASSERT(backendTex.isValid());
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400204 direct->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400205 while (!finishedBECreate) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400206 direct->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400207 }
Robert Phillips923181b2020-02-14 12:36:37 -0500208
209 callbackContext->setBackendTexture(backendTex);
210 }
211}
212
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400213void DDLPromiseImageHelper::DeleteBETexturesForPromiseImage(GrDirectContext* direct,
Robert Phillips19f466d2020-02-26 10:27:07 -0500214 PromiseImageInfo* info) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500215 if (info->isYUV()) {
216 int numPixmaps;
217 SkAssertResult(SkYUVAIndex::AreValidIndices(info->yuvaIndices(), &numPixmaps));
218 for (int j = 0; j < numPixmaps; ++j) {
219 PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
220 SkASSERT(callbackContext);
221
222 callbackContext->destroyBackendTexture();
223 SkASSERT(!callbackContext->promiseImageTexture());
224 }
225 } else {
226 PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
227 if (!callbackContext) {
228 // This texture would've been too large to fit on the GPU
229 return;
230 }
231
232 callbackContext->destroyBackendTexture();
233 SkASSERT(!callbackContext->promiseImageTexture());
234 }
235}
236
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400237void DDLPromiseImageHelper::createCallbackContexts(GrDirectContext* direct) {
238 const GrCaps* caps = direct->priv().caps();
Robert Phillips923181b2020-02-14 12:36:37 -0500239 const int maxDimension = caps->maxTextureSize();
240
241 for (int i = 0; i < fImageInfo.count(); ++i) {
242 PromiseImageInfo& info = fImageInfo[i];
243
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400244 if (info.isYUV()) {
Brian Salomon5660e8b2020-08-25 12:40:32 -0400245 int numPixmaps = info.numYUVAPlanes();
Robert Phillips923181b2020-02-14 12:36:37 -0500246
Jim Van Verth8f11e432018-10-18 14:36:59 -0400247 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400248 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -0400249
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400250 GrBackendFormat backendFormat = direct->defaultBackendFormat(yuvPixmap.colorType(),
251 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500252
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400253 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400254 new PromiseImageCallbackContext(direct, backendFormat));
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500255
Robert Phillips923181b2020-02-14 12:36:37 -0500256 info.setCallbackContext(j, std::move(callbackContext));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400257 }
Brian Salomon5660e8b2020-08-25 12:40:32 -0400258 info.initYUVAIndices();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400259 } else {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400260 const SkBitmap& baseLevel = info.baseLevel();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400261
Robert Phillips923181b2020-02-14 12:36:37 -0500262 // TODO: explicitly mark the PromiseImageInfo as too big and check in uploadAllToGPU
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400263 if (maxDimension < std::max(baseLevel.width(), baseLevel.height())) {
Robert Phillips923181b2020-02-14 12:36:37 -0500264 // This won't fit on the GPU. Fallback to a raster-backed image per tile.
265 continue;
266 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400267
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400268 GrBackendFormat backendFormat = direct->defaultBackendFormat(baseLevel.colorType(),
269 GrRenderable::kNo);
Robert Phillips923181b2020-02-14 12:36:37 -0500270 if (!caps->isFormatTexturable(backendFormat)) {
271 continue;
272 }
Robert Phillipscb1adb42019-06-10 15:09:34 -0400273
Robert Phillips923181b2020-02-14 12:36:37 -0500274 sk_sp<PromiseImageCallbackContext> callbackContext(
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400275 new PromiseImageCallbackContext(direct, backendFormat));
Robert Phillips923181b2020-02-14 12:36:37 -0500276
277 info.setCallbackContext(0, std::move(callbackContext));
278 }
279 }
280}
281
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400282void DDLPromiseImageHelper::uploadAllToGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips923181b2020-02-14 12:36:37 -0500283 if (taskGroup) {
284 for (int i = 0; i < fImageInfo.count(); ++i) {
285 PromiseImageInfo* info = &fImageInfo[i];
286
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400287 taskGroup->add([direct, info]() { CreateBETexturesForPromiseImage(direct, info); });
Robert Phillips923181b2020-02-14 12:36:37 -0500288 }
289 } else {
290 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400291 CreateBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400292 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500293 }
294}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400295
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400296void DDLPromiseImageHelper::deleteAllFromGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
Robert Phillips19f466d2020-02-26 10:27:07 -0500297 if (taskGroup) {
298 for (int i = 0; i < fImageInfo.count(); ++i) {
299 PromiseImageInfo* info = &fImageInfo[i];
300
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400301 taskGroup->add([direct, info]() { DeleteBETexturesForPromiseImage(direct, info); });
Robert Phillips19f466d2020-02-26 10:27:07 -0500302 }
303 } else {
304 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400305 DeleteBETexturesForPromiseImage(direct, &fImageInfo[i]);
Robert Phillips19f466d2020-02-26 10:27:07 -0500306 }
307 }
308}
309
Robert Phillips96601082018-05-29 16:13:26 -0400310sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
311 SkDeferredDisplayListRecorder* recorder,
312 SkData* compressedPictureData,
313 SkTArray<sk_sp<SkImage>>* promiseImages) const {
314 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
315
316 SkDeserialProcs procs;
317 procs.fImageCtx = (void*) &perRecorderContext;
Robert Phillips923181b2020-02-14 12:36:37 -0500318 procs.fImageProc = CreatePromiseImages;
Robert Phillips96601082018-05-29 16:13:26 -0400319
320 return SkPicture::MakeFromData(compressedPictureData, &procs);
321}
322
323// This generates promise images to replace the indices in the compressed picture. This
324// reconstitution is performed separately in each thread so we end up with multiple
325// promise images referring to the same GrBackendTexture.
Robert Phillips923181b2020-02-14 12:36:37 -0500326sk_sp<SkImage> DDLPromiseImageHelper::CreatePromiseImages(const void* rawData,
Robert Phillips96601082018-05-29 16:13:26 -0400327 size_t length, void* ctxIn) {
328 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
329 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
330 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
331
332 SkASSERT(length == sizeof(int));
333
334 const int* indexPtr = static_cast<const int*>(rawData);
Robert Phillips6bad7052019-12-16 15:09:57 -0500335 if (!helper->isValidID(*indexPtr)) {
336 return nullptr;
337 }
Robert Phillips96601082018-05-29 16:13:26 -0400338
339 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
340
Robert Phillips923181b2020-02-14 12:36:37 -0500341 // If there is no callback context that means 'createCallbackContexts' determined the
342 // texture wouldn't fit on the GPU. Create a separate bitmap-backed image for each thread.
343 if (!curImage.isYUV() && !curImage.callbackContext(0)) {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400344 SkASSERT(curImage.baseLevel().isImmutable());
345 return SkImage::MakeFromBitmap(curImage.baseLevel());
Robert Phillips96601082018-05-29 16:13:26 -0400346 }
Robert Phillips923181b2020-02-14 12:36:37 -0500347
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400348 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400349
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400350 sk_sp<SkImage> image;
351 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400352 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
353 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
354 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400355 // TODO: store this value somewhere?
356 int textureCount;
357 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
358 for (int i = 0; i < textureCount; ++i) {
Robert Phillips923181b2020-02-14 12:36:37 -0500359 backendFormats[i] = curImage.backendFormat(i);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500360 SkASSERT(backendFormats[i].isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400361 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400362 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400363 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400364 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400365 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400366 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000367
Brian Salomon0cc57542019-03-08 13:28:46 -0500368 image = recorder->makeYUVAPromiseTexture(
369 curImage.yuvColorSpace(),
370 backendFormats,
371 sizes,
372 curImage.yuvaIndices(),
373 curImage.overallWidth(),
374 curImage.overallHeight(),
375 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
376 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400377 PromiseImageCallbackContext::PromiseImageFulfillProc,
378 PromiseImageCallbackContext::PromiseImageReleaseProc,
379 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500380 contexts,
381 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500382 for (int i = 0; i < textureCount; ++i) {
383 curImage.callbackContext(i)->wasAddedToImage();
384 }
Robert Phillips193c4212019-03-04 12:18:53 -0500385
386#ifdef SK_DEBUG
387 {
388 // By the peekProxy contract this image should not have a single backing proxy so
389 // should return null. The call should also not trigger the conversion to RGBA.
390 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
391 SkASSERT(!yuva->peekProxy());
392 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
393 }
394#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400395 } else {
John Stiles31954bf2020-08-07 17:35:54 -0400396 const GrBackendFormat& backendFormat = curImage.backendFormat(0);
Brian Salomonf391d0f2018-12-14 09:18:50 -0500397 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400398
399 // Each DDL recorder gets its own ref on the promise callback context for the
400 // promise images it creates.
Brian Salomon0cc57542019-03-08 13:28:46 -0500401 image = recorder->makePromiseTexture(
402 backendFormat,
403 curImage.overallWidth(),
404 curImage.overallHeight(),
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400405 curImage.mipMapped(0),
Brian Salomon0cc57542019-03-08 13:28:46 -0500406 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
407 curImage.overallColorType(),
408 curImage.overallAlphaType(),
409 curImage.refOverallColorSpace(),
Robert Phillips11c67672020-04-23 15:10:03 -0400410 PromiseImageCallbackContext::PromiseImageFulfillProc,
411 PromiseImageCallbackContext::PromiseImageReleaseProc,
412 PromiseImageCallbackContext::PromiseImageDoneProc,
Brian Salomon0cc57542019-03-08 13:28:46 -0500413 (void*)curImage.refCallbackContext(0).release(),
414 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500415 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400416 }
Robert Phillips96601082018-05-29 16:13:26 -0400417 perRecorderContext->fPromiseImages->push_back(image);
418 SkASSERT(image);
419 return image;
420}
421
422int DDLPromiseImageHelper::findImage(SkImage* image) const {
423 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400424 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
425 SkASSERT(fImageInfo[i].index() == i);
426 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400427 return i;
428 }
429 }
430 return -1;
431}
432
433int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400434 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400435
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400436 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400437 image->colorType() == kBGRA_8888_SkColorType
438 ? kRGBA_8888_SkColorType
439 : image->colorType(),
440 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400441 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400442
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400443 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
444 image->uniqueID(),
445 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400446
Brian Salomonefb5f072020-07-28 21:06:43 -0400447 auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(ib->refEncodedData());
Brian Salomon5660e8b2020-08-25 12:40:32 -0400448 SkYUVAInfo yuvaInfo;
449 SkColorType colorTypes[SkYUVAInfo::kMaxPlanes];
450 size_t rowBytes[SkYUVAInfo::kMaxPlanes];
451 if (codec && codec->queryYUVAInfo(&yuvaInfo, colorTypes, rowBytes)) {
452 sk_gpu_test::YUVAPixmaps yuvaPixmaps(yuvaInfo, colorTypes, rowBytes);
453 SkAssertResult(codec->getYUVAPlanes(yuvaPixmaps.planes()));
454 SkASSERT(yuvaPixmaps.isValid());
455 newImageInfo.setYUVPlanes(std::move(yuvaPixmaps));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400456 } else {
457 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
Robert Phillipse84bffc2019-12-16 11:22:17 -0500458 if (!rasterImage) {
459 return -1;
460 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400461
462 SkBitmap tmp;
463 tmp.allocPixels(overallII);
464
465 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
466 return -1;
467 }
468
469 tmp.setImmutable();
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400470
471 // Given how the DDL testing harness works (i.e., only modifying the SkImages w/in an
472 // SKP) we don't know if a given SkImage will require mipmapping. To work around this
473 // we just try to create all the backend textures as mipmapped but, failing that, fall
474 // back to un-mipped.
Mike Reed13711eb2020-07-14 17:16:32 -0400475 std::unique_ptr<SkMipmap> mipmaps(SkMipmap::Build(tmp.pixmap(), nullptr));
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400476
477 newImageInfo.setMipLevels(tmp, std::move(mipmaps));
Robert Phillips96601082018-05-29 16:13:26 -0400478 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400479 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400480
481 return fImageInfo.count()-1;
482}
483
484int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
485 int preExistingID = this->findImage(image);
486 if (preExistingID >= 0) {
487 SkASSERT(this->isValidID(preExistingID));
488 return preExistingID;
489 }
490
491 int newID = this->addImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400492 return newID;
493}