xref: /aosp_15_r20/external/skia/tools/DDLPromiseImageHelper.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DDLPromiseImageHelper.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSerialProcs.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrContextThreadSafeProxy.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrYUVABackendTextures.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkImageGanesh.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/SkImageChromium.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkCodecImageGenerator.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCachedData.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMipmap.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTaskGroup.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/SkImage_GaneshYUVA.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImage_Base.h"
25*c8dee2aaSAndroid Build Coastguard Worker 
PromiseImageInfo(int index,uint32_t originalUniqueID,const SkImageInfo & ii)26*c8dee2aaSAndroid Build Coastguard Worker DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(int index,
27*c8dee2aaSAndroid Build Coastguard Worker                                                           uint32_t originalUniqueID,
28*c8dee2aaSAndroid Build Coastguard Worker                                                           const SkImageInfo& ii)
29*c8dee2aaSAndroid Build Coastguard Worker         : fIndex(index)
30*c8dee2aaSAndroid Build Coastguard Worker         , fOriginalUniqueID(originalUniqueID)
31*c8dee2aaSAndroid Build Coastguard Worker         , fImageInfo(ii) {
32*c8dee2aaSAndroid Build Coastguard Worker }
33*c8dee2aaSAndroid Build Coastguard Worker 
PromiseImageInfo(PromiseImageInfo && other)34*c8dee2aaSAndroid Build Coastguard Worker DDLPromiseImageHelper::PromiseImageInfo::PromiseImageInfo(PromiseImageInfo&& other)
35*c8dee2aaSAndroid Build Coastguard Worker         : fIndex(other.fIndex)
36*c8dee2aaSAndroid Build Coastguard Worker         , fOriginalUniqueID(other.fOriginalUniqueID)
37*c8dee2aaSAndroid Build Coastguard Worker         , fImageInfo(other.fImageInfo)
38*c8dee2aaSAndroid Build Coastguard Worker         , fBaseLevel(other.fBaseLevel)
39*c8dee2aaSAndroid Build Coastguard Worker         , fMipLevels(std::move(other.fMipLevels))
40*c8dee2aaSAndroid Build Coastguard Worker         , fYUVAPixmaps(std::move(other.fYUVAPixmaps)) {
41*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < SkYUVAInfo::kMaxPlanes; ++i) {
42*c8dee2aaSAndroid Build Coastguard Worker         fCallbackContexts[i] = std::move(other.fCallbackContexts[i]);
43*c8dee2aaSAndroid Build Coastguard Worker     }
44*c8dee2aaSAndroid Build Coastguard Worker }
45*c8dee2aaSAndroid Build Coastguard Worker 
~PromiseImageInfo()46*c8dee2aaSAndroid Build Coastguard Worker DDLPromiseImageHelper::PromiseImageInfo::~PromiseImageInfo() {}
47*c8dee2aaSAndroid Build Coastguard Worker 
normalMipLevels() const48*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPixmap[]> DDLPromiseImageHelper::PromiseImageInfo::normalMipLevels() const {
49*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!this->isYUV());
50*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkPixmap[]> pixmaps(new SkPixmap[this->numMipLevels()]);
51*c8dee2aaSAndroid Build Coastguard Worker     pixmaps[0] = fBaseLevel.pixmap();
52*c8dee2aaSAndroid Build Coastguard Worker     if (fMipLevels) {
53*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fMipLevels->countLevels(); ++i) {
54*c8dee2aaSAndroid Build Coastguard Worker             SkMipmap::Level mipLevel;
55*c8dee2aaSAndroid Build Coastguard Worker             fMipLevels->getLevel(i, &mipLevel);
56*c8dee2aaSAndroid Build Coastguard Worker             pixmaps[i+1] = mipLevel.fPixmap;
57*c8dee2aaSAndroid Build Coastguard Worker         }
58*c8dee2aaSAndroid Build Coastguard Worker     }
59*c8dee2aaSAndroid Build Coastguard Worker     return pixmaps;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker 
numMipLevels() const62*c8dee2aaSAndroid Build Coastguard Worker int DDLPromiseImageHelper::PromiseImageInfo::numMipLevels() const {
63*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!this->isYUV());
64*c8dee2aaSAndroid Build Coastguard Worker     return fMipLevels ? fMipLevels->countLevels()+1 : 1;
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
setMipLevels(const SkBitmap & baseLevel,std::unique_ptr<SkMipmap> mipLevels)67*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::PromiseImageInfo::setMipLevels(const SkBitmap& baseLevel,
68*c8dee2aaSAndroid Build Coastguard Worker                                                            std::unique_ptr<SkMipmap> mipLevels) {
69*c8dee2aaSAndroid Build Coastguard Worker     fBaseLevel = baseLevel;
70*c8dee2aaSAndroid Build Coastguard Worker     fMipLevels = std::move(mipLevels);
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
~PromiseImageCallbackContext()74*c8dee2aaSAndroid Build Coastguard Worker PromiseImageCallbackContext::~PromiseImageCallbackContext() {
75*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fDoneCnt == fNumImages);
76*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fTotalFulfills || fDoneCnt);
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker     if (fPromiseImageTexture) {
79*c8dee2aaSAndroid Build Coastguard Worker         fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker 
setBackendTexture(const GrBackendTexture & backendTexture)83*c8dee2aaSAndroid Build Coastguard Worker void PromiseImageCallbackContext::setBackendTexture(const GrBackendTexture& backendTexture) {
84*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fPromiseImageTexture);
85*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fBackendFormat == backendTexture.getBackendFormat());
86*c8dee2aaSAndroid Build Coastguard Worker     fPromiseImageTexture = GrPromiseImageTexture::Make(backendTexture);
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker 
destroyBackendTexture()89*c8dee2aaSAndroid Build Coastguard Worker void PromiseImageCallbackContext::destroyBackendTexture() {
90*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker     if (fPromiseImageTexture) {
93*c8dee2aaSAndroid Build Coastguard Worker         fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker     fPromiseImageTexture = nullptr;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
99*c8dee2aaSAndroid Build Coastguard Worker 
recreateSKP(GrDirectContext * dContext,SkPicture * inputPicture)100*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> DDLPromiseImageHelper::recreateSKP(GrDirectContext* dContext,
101*c8dee2aaSAndroid Build Coastguard Worker                                                     SkPicture* inputPicture) {
102*c8dee2aaSAndroid Build Coastguard Worker     SkSerialProcs procs;
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageCtx = this;
105*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
106*c8dee2aaSAndroid Build Coastguard Worker         auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker         int id = helper->findOrDefineImage(image);
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker         // Even if 'id' is invalid (i.e., -1) write it to the SKP
111*c8dee2aaSAndroid Build Coastguard Worker         return SkData::MakeWithCopy(&id, sizeof(id));
112*c8dee2aaSAndroid Build Coastguard Worker     };
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> compressedPictureData = inputPicture->serialize(&procs);
115*c8dee2aaSAndroid Build Coastguard Worker     if (!compressedPictureData) {
116*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
117*c8dee2aaSAndroid Build Coastguard Worker     }
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker     this->createCallbackContexts(dContext);
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     return this->reinflateSKP(dContext->threadSafeProxy(), compressedPictureData.get());
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker 
create_yuva_texture(GrDirectContext * direct,const SkPixmap & pm,int texIndex)124*c8dee2aaSAndroid Build Coastguard Worker static GrBackendTexture create_yuva_texture(GrDirectContext* direct,
125*c8dee2aaSAndroid Build Coastguard Worker                                             const SkPixmap& pm,
126*c8dee2aaSAndroid Build Coastguard Worker                                             int texIndex) {
127*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(texIndex >= 0 && texIndex <= 3);
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     bool finishedBECreate = false;
130*c8dee2aaSAndroid Build Coastguard Worker     auto markFinished = [](void* context) {
131*c8dee2aaSAndroid Build Coastguard Worker         *(bool*)context = true;
132*c8dee2aaSAndroid Build Coastguard Worker     };
133*c8dee2aaSAndroid Build Coastguard Worker     auto beTex = direct->createBackendTexture(pm,
134*c8dee2aaSAndroid Build Coastguard Worker                                               kTopLeft_GrSurfaceOrigin,
135*c8dee2aaSAndroid Build Coastguard Worker                                               GrRenderable::kNo,
136*c8dee2aaSAndroid Build Coastguard Worker                                               GrProtected::kNo,
137*c8dee2aaSAndroid Build Coastguard Worker                                               markFinished,
138*c8dee2aaSAndroid Build Coastguard Worker                                               &finishedBECreate,
139*c8dee2aaSAndroid Build Coastguard Worker                                               /*label=*/"CreateYuvaTexture");
140*c8dee2aaSAndroid Build Coastguard Worker     if (beTex.isValid()) {
141*c8dee2aaSAndroid Build Coastguard Worker         direct->submit();
142*c8dee2aaSAndroid Build Coastguard Worker         while (!finishedBECreate) {
143*c8dee2aaSAndroid Build Coastguard Worker             direct->checkAsyncWorkCompletion();
144*c8dee2aaSAndroid Build Coastguard Worker         }
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker     return beTex;
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker 
149*c8dee2aaSAndroid Build Coastguard Worker /*
150*c8dee2aaSAndroid Build Coastguard Worker  * Create backend textures and upload data to them for all the textures required to satisfy
151*c8dee2aaSAndroid Build Coastguard Worker  * a single promise image.
152*c8dee2aaSAndroid Build Coastguard Worker  * For YUV textures this will result in up to 4 actual textures.
153*c8dee2aaSAndroid Build Coastguard Worker  */
CreateBETexturesForPromiseImage(GrDirectContext * direct,PromiseImageInfo * info)154*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::CreateBETexturesForPromiseImage(GrDirectContext* direct,
155*c8dee2aaSAndroid Build Coastguard Worker                                                             PromiseImageInfo* info) {
156*c8dee2aaSAndroid Build Coastguard Worker     if (info->isYUV()) {
157*c8dee2aaSAndroid Build Coastguard Worker         int numPixmaps = info->yuvaInfo().numPlanes();
158*c8dee2aaSAndroid Build Coastguard Worker         for (int j = 0; j < numPixmaps; ++j) {
159*c8dee2aaSAndroid Build Coastguard Worker             const SkPixmap& yuvPixmap = info->yuvPixmap(j);
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker             PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
162*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(callbackContext);
163*c8dee2aaSAndroid Build Coastguard Worker 
164*c8dee2aaSAndroid Build Coastguard Worker             // DDL TODO: what should we do with mipmapped YUV images
165*c8dee2aaSAndroid Build Coastguard Worker             callbackContext->setBackendTexture(create_yuva_texture(direct, yuvPixmap, j));
166*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(callbackContext->promiseImageTexture());
167*c8dee2aaSAndroid Build Coastguard Worker         }
168*c8dee2aaSAndroid Build Coastguard Worker     } else {
169*c8dee2aaSAndroid Build Coastguard Worker         PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
170*c8dee2aaSAndroid Build Coastguard Worker         if (!callbackContext) {
171*c8dee2aaSAndroid Build Coastguard Worker             // This texture would've been too large to fit on the GPU
172*c8dee2aaSAndroid Build Coastguard Worker             return;
173*c8dee2aaSAndroid Build Coastguard Worker         }
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<SkPixmap[]> mipLevels = info->normalMipLevels();
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         bool finishedBECreate = false;
178*c8dee2aaSAndroid Build Coastguard Worker         auto markFinished = [](void* context) {
179*c8dee2aaSAndroid Build Coastguard Worker             *(bool*)context = true;
180*c8dee2aaSAndroid Build Coastguard Worker         };
181*c8dee2aaSAndroid Build Coastguard Worker         auto backendTex = direct->createBackendTexture(mipLevels.get(),
182*c8dee2aaSAndroid Build Coastguard Worker                                                        info->numMipLevels(),
183*c8dee2aaSAndroid Build Coastguard Worker                                                        kTopLeft_GrSurfaceOrigin,
184*c8dee2aaSAndroid Build Coastguard Worker                                                        GrRenderable::kNo,
185*c8dee2aaSAndroid Build Coastguard Worker                                                        GrProtected::kNo,
186*c8dee2aaSAndroid Build Coastguard Worker                                                        markFinished,
187*c8dee2aaSAndroid Build Coastguard Worker                                                        &finishedBECreate,
188*c8dee2aaSAndroid Build Coastguard Worker                                                        /*label=*/"CreateBETexturesForPromiseImage");
189*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(backendTex.isValid());
190*c8dee2aaSAndroid Build Coastguard Worker         direct->submit();
191*c8dee2aaSAndroid Build Coastguard Worker         while (!finishedBECreate) {
192*c8dee2aaSAndroid Build Coastguard Worker             direct->checkAsyncWorkCompletion();
193*c8dee2aaSAndroid Build Coastguard Worker         }
194*c8dee2aaSAndroid Build Coastguard Worker 
195*c8dee2aaSAndroid Build Coastguard Worker         callbackContext->setBackendTexture(backendTex);
196*c8dee2aaSAndroid Build Coastguard Worker     }
197*c8dee2aaSAndroid Build Coastguard Worker }
198*c8dee2aaSAndroid Build Coastguard Worker 
DeleteBETexturesForPromiseImage(PromiseImageInfo * info)199*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::DeleteBETexturesForPromiseImage(PromiseImageInfo* info) {
200*c8dee2aaSAndroid Build Coastguard Worker     if (info->isYUV()) {
201*c8dee2aaSAndroid Build Coastguard Worker         int numPixmaps = info->yuvaInfo().numPlanes();
202*c8dee2aaSAndroid Build Coastguard Worker         for (int j = 0; j < numPixmaps; ++j) {
203*c8dee2aaSAndroid Build Coastguard Worker             PromiseImageCallbackContext* callbackContext = info->callbackContext(j);
204*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(callbackContext);
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker             callbackContext->destroyBackendTexture();
207*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!callbackContext->promiseImageTexture());
208*c8dee2aaSAndroid Build Coastguard Worker         }
209*c8dee2aaSAndroid Build Coastguard Worker     } else {
210*c8dee2aaSAndroid Build Coastguard Worker         PromiseImageCallbackContext* callbackContext = info->callbackContext(0);
211*c8dee2aaSAndroid Build Coastguard Worker         if (!callbackContext) {
212*c8dee2aaSAndroid Build Coastguard Worker             // This texture would've been too large to fit on the GPU
213*c8dee2aaSAndroid Build Coastguard Worker             return;
214*c8dee2aaSAndroid Build Coastguard Worker         }
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker         callbackContext->destroyBackendTexture();
217*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!callbackContext->promiseImageTexture());
218*c8dee2aaSAndroid Build Coastguard Worker     }
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker 
createCallbackContexts(GrDirectContext * direct)221*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::createCallbackContexts(GrDirectContext* direct) {
222*c8dee2aaSAndroid Build Coastguard Worker     const GrCaps* caps = direct->priv().caps();
223*c8dee2aaSAndroid Build Coastguard Worker     const int maxDimension = caps->maxTextureSize();
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fImageInfo.size(); ++i) {
226*c8dee2aaSAndroid Build Coastguard Worker         PromiseImageInfo& info = fImageInfo[i];
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker         if (info.isYUV()) {
229*c8dee2aaSAndroid Build Coastguard Worker             int numPixmaps = info.yuvaInfo().numPlanes();
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < numPixmaps; ++j) {
232*c8dee2aaSAndroid Build Coastguard Worker                 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker                 GrBackendFormat backendFormat = direct->defaultBackendFormat(yuvPixmap.colorType(),
235*c8dee2aaSAndroid Build Coastguard Worker                                                                              GrRenderable::kNo);
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker                 sk_sp<PromiseImageCallbackContext> callbackContext(
238*c8dee2aaSAndroid Build Coastguard Worker                     new PromiseImageCallbackContext(direct, backendFormat));
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker                 info.setCallbackContext(j, std::move(callbackContext));
241*c8dee2aaSAndroid Build Coastguard Worker             }
242*c8dee2aaSAndroid Build Coastguard Worker         } else {
243*c8dee2aaSAndroid Build Coastguard Worker             const SkBitmap& baseLevel = info.baseLevel();
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker             // TODO: explicitly mark the PromiseImageInfo as too big and check in uploadAllToGPU
246*c8dee2aaSAndroid Build Coastguard Worker             if (maxDimension < std::max(baseLevel.width(), baseLevel.height())) {
247*c8dee2aaSAndroid Build Coastguard Worker                 // This won't fit on the GPU. Fallback to a raster-backed image per tile.
248*c8dee2aaSAndroid Build Coastguard Worker                 continue;
249*c8dee2aaSAndroid Build Coastguard Worker             }
250*c8dee2aaSAndroid Build Coastguard Worker 
251*c8dee2aaSAndroid Build Coastguard Worker             GrBackendFormat backendFormat = direct->defaultBackendFormat(baseLevel.colorType(),
252*c8dee2aaSAndroid Build Coastguard Worker                                                                          GrRenderable::kNo);
253*c8dee2aaSAndroid Build Coastguard Worker             if (!caps->isFormatTexturable(backendFormat, GrTextureType::k2D)) {
254*c8dee2aaSAndroid Build Coastguard Worker                 continue;
255*c8dee2aaSAndroid Build Coastguard Worker             }
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<PromiseImageCallbackContext> callbackContext(
258*c8dee2aaSAndroid Build Coastguard Worker                 new PromiseImageCallbackContext(direct, backendFormat));
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker             info.setCallbackContext(0, std::move(callbackContext));
261*c8dee2aaSAndroid Build Coastguard Worker         }
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker }
264*c8dee2aaSAndroid Build Coastguard Worker 
uploadAllToGPU(SkTaskGroup * taskGroup,GrDirectContext * direct)265*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::uploadAllToGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
266*c8dee2aaSAndroid Build Coastguard Worker     if (taskGroup) {
267*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fImageInfo.size(); ++i) {
268*c8dee2aaSAndroid Build Coastguard Worker             PromiseImageInfo* info = &fImageInfo[i];
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker             taskGroup->add([direct, info]() { CreateBETexturesForPromiseImage(direct, info); });
271*c8dee2aaSAndroid Build Coastguard Worker         }
272*c8dee2aaSAndroid Build Coastguard Worker     } else {
273*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fImageInfo.size(); ++i) {
274*c8dee2aaSAndroid Build Coastguard Worker             CreateBETexturesForPromiseImage(direct, &fImageInfo[i]);
275*c8dee2aaSAndroid Build Coastguard Worker         }
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker 
deleteAllFromGPU(SkTaskGroup * taskGroup,GrDirectContext * direct)279*c8dee2aaSAndroid Build Coastguard Worker void DDLPromiseImageHelper::deleteAllFromGPU(SkTaskGroup* taskGroup, GrDirectContext* direct) {
280*c8dee2aaSAndroid Build Coastguard Worker     if (taskGroup) {
281*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fImageInfo.size(); ++i) {
282*c8dee2aaSAndroid Build Coastguard Worker             PromiseImageInfo* info = &fImageInfo[i];
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker             taskGroup->add([info]() { DeleteBETexturesForPromiseImage(info); });
285*c8dee2aaSAndroid Build Coastguard Worker         }
286*c8dee2aaSAndroid Build Coastguard Worker     } else {
287*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fImageInfo.size(); ++i) {
288*c8dee2aaSAndroid Build Coastguard Worker             DeleteBETexturesForPromiseImage(&fImageInfo[i]);
289*c8dee2aaSAndroid Build Coastguard Worker         }
290*c8dee2aaSAndroid Build Coastguard Worker     }
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker 
reinflateSKP(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,SkData * compressedPictureData)293*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
294*c8dee2aaSAndroid Build Coastguard Worker                                                    sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
295*c8dee2aaSAndroid Build Coastguard Worker                                                    SkData* compressedPictureData) {
296*c8dee2aaSAndroid Build Coastguard Worker     DeserialImageProcContext procContext { std::move(threadSafeProxy), this };
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker     SkDeserialProcs procs;
299*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageCtx = (void*) &procContext;
300*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageProc = CreatePromiseImages;
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker     return SkPicture::MakeFromData(compressedPictureData, &procs);
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker // This generates promise images to replace the indices in the compressed picture.
CreatePromiseImages(const void * rawData,size_t length,void * ctxIn)306*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> DDLPromiseImageHelper::CreatePromiseImages(const void* rawData,
307*c8dee2aaSAndroid Build Coastguard Worker                                                           size_t length,
308*c8dee2aaSAndroid Build Coastguard Worker                                                           void* ctxIn) {
309*c8dee2aaSAndroid Build Coastguard Worker     DeserialImageProcContext* procContext = static_cast<DeserialImageProcContext*>(ctxIn);
310*c8dee2aaSAndroid Build Coastguard Worker     DDLPromiseImageHelper* helper = procContext->fHelper;
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(length == sizeof(int));
313*c8dee2aaSAndroid Build Coastguard Worker 
314*c8dee2aaSAndroid Build Coastguard Worker     const int* indexPtr = static_cast<const int*>(rawData);
315*c8dee2aaSAndroid Build Coastguard Worker     if (!helper->isValidID(*indexPtr)) {
316*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
317*c8dee2aaSAndroid Build Coastguard Worker     }
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker     const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
320*c8dee2aaSAndroid Build Coastguard Worker 
321*c8dee2aaSAndroid Build Coastguard Worker     // If there is no callback context that means 'createCallbackContexts' determined the
322*c8dee2aaSAndroid Build Coastguard Worker     // texture wouldn't fit on the GPU. Create a bitmap-backed image.
323*c8dee2aaSAndroid Build Coastguard Worker     if (!curImage.isYUV() && !curImage.callbackContext(0)) {
324*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(curImage.baseLevel().isImmutable());
325*c8dee2aaSAndroid Build Coastguard Worker         return curImage.baseLevel().asImage();
326*c8dee2aaSAndroid Build Coastguard Worker     }
327*c8dee2aaSAndroid Build Coastguard Worker 
328*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(curImage.index() == *indexPtr);
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> image;
331*c8dee2aaSAndroid Build Coastguard Worker     if (curImage.isYUV()) {
332*c8dee2aaSAndroid Build Coastguard Worker         GrBackendFormat backendFormats[SkYUVAInfo::kMaxPlanes];
333*c8dee2aaSAndroid Build Coastguard Worker         const SkYUVAInfo& yuvaInfo = curImage.yuvaInfo();
334*c8dee2aaSAndroid Build Coastguard Worker         void* contexts[SkYUVAInfo::kMaxPlanes] = {nullptr, nullptr, nullptr, nullptr};
335*c8dee2aaSAndroid Build Coastguard Worker         int textureCount = yuvaInfo.numPlanes();
336*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < textureCount; ++i) {
337*c8dee2aaSAndroid Build Coastguard Worker             backendFormats[i] = curImage.backendFormat(i);
338*c8dee2aaSAndroid Build Coastguard Worker             contexts[i] = curImage.refCallbackContext(i).release();
339*c8dee2aaSAndroid Build Coastguard Worker         }
340*c8dee2aaSAndroid Build Coastguard Worker         GrYUVABackendTextureInfo yuvaBackendTextures(
341*c8dee2aaSAndroid Build Coastguard Worker                 yuvaInfo, backendFormats, skgpu::Mipmapped::kNo, kTopLeft_GrSurfaceOrigin);
342*c8dee2aaSAndroid Build Coastguard Worker         image = SkImages::PromiseTextureFromYUVA(
343*c8dee2aaSAndroid Build Coastguard Worker                 procContext->fThreadSafeProxy,
344*c8dee2aaSAndroid Build Coastguard Worker                 yuvaBackendTextures,
345*c8dee2aaSAndroid Build Coastguard Worker                 curImage.refOverallColorSpace(),
346*c8dee2aaSAndroid Build Coastguard Worker                 PromiseImageCallbackContext::PromiseImageFulfillProc,
347*c8dee2aaSAndroid Build Coastguard Worker                 PromiseImageCallbackContext::PromiseImageReleaseProc,
348*c8dee2aaSAndroid Build Coastguard Worker                 contexts);
349*c8dee2aaSAndroid Build Coastguard Worker         if (!image) {
350*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
351*c8dee2aaSAndroid Build Coastguard Worker         }
352*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < textureCount; ++i) {
353*c8dee2aaSAndroid Build Coastguard Worker             curImage.callbackContext(i)->wasAddedToImage();
354*c8dee2aaSAndroid Build Coastguard Worker         }
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     } else {
357*c8dee2aaSAndroid Build Coastguard Worker         const GrBackendFormat& backendFormat = curImage.backendFormat(0);
358*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(backendFormat.isValid());
359*c8dee2aaSAndroid Build Coastguard Worker 
360*c8dee2aaSAndroid Build Coastguard Worker         image = SkImages::PromiseTextureFrom(procContext->fThreadSafeProxy,
361*c8dee2aaSAndroid Build Coastguard Worker                                              backendFormat,
362*c8dee2aaSAndroid Build Coastguard Worker                                              curImage.overallDimensions(),
363*c8dee2aaSAndroid Build Coastguard Worker                                              curImage.mipmapped(0),
364*c8dee2aaSAndroid Build Coastguard Worker                                              GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
365*c8dee2aaSAndroid Build Coastguard Worker                                              curImage.overallColorType(),
366*c8dee2aaSAndroid Build Coastguard Worker                                              curImage.overallAlphaType(),
367*c8dee2aaSAndroid Build Coastguard Worker                                              curImage.refOverallColorSpace(),
368*c8dee2aaSAndroid Build Coastguard Worker                                              PromiseImageCallbackContext::PromiseImageFulfillProc,
369*c8dee2aaSAndroid Build Coastguard Worker                                              PromiseImageCallbackContext::PromiseImageReleaseProc,
370*c8dee2aaSAndroid Build Coastguard Worker                                              (void*)curImage.refCallbackContext(0).release());
371*c8dee2aaSAndroid Build Coastguard Worker         curImage.callbackContext(0)->wasAddedToImage();
372*c8dee2aaSAndroid Build Coastguard Worker     }
373*c8dee2aaSAndroid Build Coastguard Worker     helper->fPromiseImages.push_back(image);
374*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(image);
375*c8dee2aaSAndroid Build Coastguard Worker     return image;
376*c8dee2aaSAndroid Build Coastguard Worker }
377*c8dee2aaSAndroid Build Coastguard Worker 
findImage(SkImage * image) const378*c8dee2aaSAndroid Build Coastguard Worker int DDLPromiseImageHelper::findImage(SkImage* image) const {
379*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fImageInfo.size(); ++i) {
380*c8dee2aaSAndroid Build Coastguard Worker         if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
381*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fImageInfo[i].index() == i);
382*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
383*c8dee2aaSAndroid Build Coastguard Worker             return i;
384*c8dee2aaSAndroid Build Coastguard Worker         }
385*c8dee2aaSAndroid Build Coastguard Worker     }
386*c8dee2aaSAndroid Build Coastguard Worker     return -1;
387*c8dee2aaSAndroid Build Coastguard Worker }
388*c8dee2aaSAndroid Build Coastguard Worker 
addImage(SkImage * image)389*c8dee2aaSAndroid Build Coastguard Worker int DDLPromiseImageHelper::addImage(SkImage* image) {
390*c8dee2aaSAndroid Build Coastguard Worker     SkImage_Base* ib = as_IB(image);
391*c8dee2aaSAndroid Build Coastguard Worker 
392*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
393*c8dee2aaSAndroid Build Coastguard Worker                                               image->colorType() == kBGRA_8888_SkColorType
394*c8dee2aaSAndroid Build Coastguard Worker                                                         ? kRGBA_8888_SkColorType
395*c8dee2aaSAndroid Build Coastguard Worker                                                         : image->colorType(),
396*c8dee2aaSAndroid Build Coastguard Worker                                               image->alphaType(),
397*c8dee2aaSAndroid Build Coastguard Worker                                               image->refColorSpace());
398*c8dee2aaSAndroid Build Coastguard Worker 
399*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.size(),
400*c8dee2aaSAndroid Build Coastguard Worker                                                              image->uniqueID(),
401*c8dee2aaSAndroid Build Coastguard Worker                                                              overallII);
402*c8dee2aaSAndroid Build Coastguard Worker 
403*c8dee2aaSAndroid Build Coastguard Worker     auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(ib->refEncodedData());
404*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAPixmapInfo yuvaInfo;
405*c8dee2aaSAndroid Build Coastguard Worker     if (codec && codec->queryYUVAInfo(fSupportedYUVADataTypes, &yuvaInfo)) {
406*c8dee2aaSAndroid Build Coastguard Worker         auto yuvaPixmaps = SkYUVAPixmaps::Allocate(yuvaInfo);
407*c8dee2aaSAndroid Build Coastguard Worker         if (!codec->getYUVAPlanes(yuvaPixmaps)) {
408*c8dee2aaSAndroid Build Coastguard Worker             return -1;
409*c8dee2aaSAndroid Build Coastguard Worker         }
410*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(yuvaPixmaps.isValid());
411*c8dee2aaSAndroid Build Coastguard Worker         newImageInfo.setYUVPlanes(std::move(yuvaPixmaps));
412*c8dee2aaSAndroid Build Coastguard Worker     } else {
413*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
414*c8dee2aaSAndroid Build Coastguard Worker         if (!rasterImage) {
415*c8dee2aaSAndroid Build Coastguard Worker             return -1;
416*c8dee2aaSAndroid Build Coastguard Worker         }
417*c8dee2aaSAndroid Build Coastguard Worker 
418*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap tmp;
419*c8dee2aaSAndroid Build Coastguard Worker         tmp.allocPixels(overallII);
420*c8dee2aaSAndroid Build Coastguard Worker 
421*c8dee2aaSAndroid Build Coastguard Worker         if (!rasterImage->readPixels(nullptr, tmp.pixmap(), 0, 0)) {
422*c8dee2aaSAndroid Build Coastguard Worker             return -1;
423*c8dee2aaSAndroid Build Coastguard Worker         }
424*c8dee2aaSAndroid Build Coastguard Worker 
425*c8dee2aaSAndroid Build Coastguard Worker         tmp.setImmutable();
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker         // Given how the DDL testing harness works (i.e., only modifying the SkImages w/in an
428*c8dee2aaSAndroid Build Coastguard Worker         // SKP) we don't know if a given SkImage will require mipmapping. To work around this
429*c8dee2aaSAndroid Build Coastguard Worker         // we just try to create all the backend textures as mipmapped but, failing that, fall
430*c8dee2aaSAndroid Build Coastguard Worker         // back to un-mipped.
431*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<SkMipmap> mipmaps(SkMipmap::Build(tmp.pixmap(), nullptr));
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker         newImageInfo.setMipLevels(tmp, std::move(mipmaps));
434*c8dee2aaSAndroid Build Coastguard Worker     }
435*c8dee2aaSAndroid Build Coastguard Worker     // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker     return fImageInfo.size()-1;
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker 
findOrDefineImage(SkImage * image)440*c8dee2aaSAndroid Build Coastguard Worker int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
441*c8dee2aaSAndroid Build Coastguard Worker     int preExistingID = this->findImage(image);
442*c8dee2aaSAndroid Build Coastguard Worker     if (preExistingID >= 0) {
443*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(this->isValidID(preExistingID));
444*c8dee2aaSAndroid Build Coastguard Worker         return preExistingID;
445*c8dee2aaSAndroid Build Coastguard Worker     }
446*c8dee2aaSAndroid Build Coastguard Worker 
447*c8dee2aaSAndroid Build Coastguard Worker     int newID = this->addImage(image);
448*c8dee2aaSAndroid Build Coastguard Worker     return newID;
449*c8dee2aaSAndroid Build Coastguard Worker }
450