/src/skia/tools/DDLPromiseImageHelper.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
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 | | |
8 | | #ifndef PromiseImageHelper_DEFINED |
9 | | #define PromiseImageHelper_DEFINED |
10 | | |
11 | | #include "include/core/SkBitmap.h" |
12 | | #include "include/core/SkRefCnt.h" |
13 | | #include "include/core/SkYUVAPixmaps.h" |
14 | | #include "include/gpu/GrBackendSurface.h" |
15 | | #include "include/private/base/SkTArray.h" |
16 | | #include "include/private/chromium/GrPromiseImageTexture.h" |
17 | | #include "src/base/SkTLazy.h" |
18 | | #include "src/core/SkCachedData.h" |
19 | | |
20 | | class GrContextThreadSafeProxy; |
21 | | class GrDirectContext; |
22 | | class SkImage; |
23 | | class SkMipmap; |
24 | | class SkPicture; |
25 | | class SkTaskGroup; |
26 | | |
27 | | // This class acts as a proxy for a GrBackendTexture that backs an image. |
28 | | // Whenever a promise image is created for the image, the promise image receives a ref to |
29 | | // potentially several of these objects. Once all the promise images receive their done |
30 | | // callbacks this object is deleted - removing the GrBackendTexture from VRAM. |
31 | | // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds |
32 | | // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done |
33 | | // it drops all of its refs (via "reset"). |
34 | | class PromiseImageCallbackContext : public SkRefCnt { |
35 | | public: |
36 | | PromiseImageCallbackContext(GrDirectContext* direct, GrBackendFormat backendFormat) |
37 | | : fContext(direct) |
38 | 0 | , fBackendFormat(backendFormat) {} |
39 | | |
40 | | ~PromiseImageCallbackContext() override; |
41 | | |
42 | 0 | const GrBackendFormat& backendFormat() const { return fBackendFormat; } |
43 | | |
44 | | void setBackendTexture(const GrBackendTexture& backendTexture); |
45 | | |
46 | | void destroyBackendTexture(); |
47 | | |
48 | 0 | sk_sp<GrPromiseImageTexture> fulfill() { |
49 | 0 | ++fTotalFulfills; |
50 | 0 | return fPromiseImageTexture; |
51 | 0 | } |
52 | | |
53 | 0 | void release() { |
54 | 0 | ++fDoneCnt; |
55 | 0 | SkASSERT(fDoneCnt <= fNumImages); |
56 | 0 | } Unexecuted instantiation: PromiseImageCallbackContext::release() Unexecuted instantiation: PromiseImageCallbackContext::release() |
57 | | |
58 | 0 | void wasAddedToImage() { fNumImages++; } |
59 | | |
60 | 0 | const GrPromiseImageTexture* promiseImageTexture() const { |
61 | 0 | return fPromiseImageTexture.get(); |
62 | 0 | } |
63 | | |
64 | 0 | static sk_sp<GrPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) { |
65 | 0 | auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext); |
66 | 0 | return callbackContext->fulfill(); |
67 | 0 | } |
68 | | |
69 | 0 | static void PromiseImageReleaseProc(void* textureContext) { |
70 | 0 | auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext); |
71 | 0 | callbackContext->release(); |
72 | 0 | callbackContext->unref(); |
73 | 0 | } |
74 | | |
75 | | private: |
76 | | GrDirectContext* fContext; |
77 | | GrBackendFormat fBackendFormat; |
78 | | sk_sp<GrPromiseImageTexture> fPromiseImageTexture; |
79 | | int fNumImages = 0; |
80 | | int fTotalFulfills = 0; |
81 | | int fDoneCnt = 0; |
82 | | |
83 | | using INHERITED = SkRefCnt; |
84 | | }; |
85 | | |
86 | | // This class consolidates tracking & extraction of the original image data from an skp, |
87 | | // the upload of said data to the GPU and the fulfillment of promise images. |
88 | | // |
89 | | // The way this works is: |
90 | | // the original skp is converted to SkData and all its image info is extracted into this |
91 | | // class and only indices into this class are left in the SkData |
92 | | // the PromiseImageCallbackContexts are created for each image |
93 | | // the SkData is then reinflated into an SkPicture with promise images replacing all the indices |
94 | | // (all in recreateSKP) |
95 | | // |
96 | | // Prior to replaying in threads, all the images are uploaded to the gpu |
97 | | // (in uploadAllToGPU) |
98 | | // |
99 | | // This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts |
100 | | // |
101 | | // Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images |
102 | | // are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed |
103 | | // from VRAM |
104 | | // |
105 | | // Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until |
106 | | // all the replaying is complete. This will pin the GrBackendTextures in VRAM. |
107 | | class DDLPromiseImageHelper { |
108 | | public: |
109 | | DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes& supportedYUVADataTypes) |
110 | 0 | : fSupportedYUVADataTypes(supportedYUVADataTypes) {} |
111 | | ~DDLPromiseImageHelper() = default; |
112 | | |
113 | | // Convert the input SkPicture into a new one which has promise images rather than live |
114 | | // images. |
115 | | sk_sp<SkPicture> recreateSKP(GrDirectContext*, SkPicture*); |
116 | | |
117 | | void uploadAllToGPU(SkTaskGroup*, GrDirectContext*); |
118 | | void deleteAllFromGPU(SkTaskGroup*, GrDirectContext*); |
119 | | |
120 | | // Remove this class' refs on the promise images and the PromiseImageCallbackContexts |
121 | 0 | void reset() { |
122 | 0 | fImageInfo.clear(); |
123 | 0 | fPromiseImages.clear(); |
124 | 0 | } |
125 | | |
126 | | private: |
127 | | void createCallbackContexts(GrDirectContext*); |
128 | | // reinflate a deflated SKP, replacing all the indices with promise images. |
129 | | sk_sp<SkPicture> reinflateSKP(sk_sp<GrContextThreadSafeProxy>, SkData* deflatedSKP); |
130 | | |
131 | | // This is the information extracted into this class from the parsing of the skp file. |
132 | | // Once it has all been uploaded to the GPU and distributed to the promise images, it |
133 | | // is all dropped via "reset". |
134 | | class PromiseImageInfo { |
135 | | public: |
136 | | PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii); |
137 | | PromiseImageInfo(PromiseImageInfo&& other); |
138 | | ~PromiseImageInfo(); |
139 | | |
140 | 0 | int index() const { return fIndex; } |
141 | 0 | uint32_t originalUniqueID() const { return fOriginalUniqueID; } |
142 | 0 | bool isYUV() const { return fYUVAPixmaps.isValid(); } |
143 | | |
144 | 0 | SkISize overallDimensions() const { return fImageInfo.dimensions(); } |
145 | 0 | SkColorType overallColorType() const { return fImageInfo.colorType(); } |
146 | 0 | SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); } |
147 | 0 | sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); } |
148 | | |
149 | 0 | const SkYUVAInfo& yuvaInfo() const { return fYUVAPixmaps.yuvaInfo(); } |
150 | | |
151 | 0 | const SkPixmap& yuvPixmap(int index) const { |
152 | 0 | SkASSERT(this->isYUV()); |
153 | 0 | return fYUVAPixmaps.planes()[index]; |
154 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::yuvPixmap(int) const Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::yuvPixmap(int) const |
155 | | |
156 | 0 | const SkBitmap& baseLevel() const { |
157 | 0 | SkASSERT(!this->isYUV()); |
158 | 0 | return fBaseLevel; |
159 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::baseLevel() const Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::baseLevel() const |
160 | | // This returns an array of all the available mipLevels - suitable for passing into |
161 | | // createBackendTexture. |
162 | | std::unique_ptr<SkPixmap[]> normalMipLevels() const; |
163 | | int numMipLevels() const; |
164 | | |
165 | 0 | void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) { |
166 | 0 | SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1)); |
167 | 0 | fCallbackContexts[index] = callbackContext; |
168 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::setCallbackContext(int, sk_sp<PromiseImageCallbackContext>) Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::setCallbackContext(int, sk_sp<PromiseImageCallbackContext>) |
169 | 0 | PromiseImageCallbackContext* callbackContext(int index) const { |
170 | 0 | SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1)); |
171 | 0 | return fCallbackContexts[index].get(); |
172 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::callbackContext(int) const Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::callbackContext(int) const |
173 | 0 | sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const { |
174 | 0 | SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1)); |
175 | 0 | return fCallbackContexts[index]; |
176 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::refCallbackContext(int) const Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::refCallbackContext(int) const |
177 | | |
178 | 0 | skgpu::Mipmapped mipmapped(int index) const { |
179 | 0 | if (this->isYUV()) { |
180 | 0 | return skgpu::Mipmapped::kNo; |
181 | 0 | } |
182 | 0 | return fMipLevels ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo; |
183 | 0 | } |
184 | 0 | const GrBackendFormat& backendFormat(int index) const { |
185 | 0 | SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1)); |
186 | 0 | return fCallbackContexts[index]->backendFormat(); |
187 | 0 | } Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::backendFormat(int) const Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::backendFormat(int) const |
188 | 0 | const GrPromiseImageTexture* promiseTexture(int index) const { |
189 | 0 | SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1)); |
190 | 0 | return fCallbackContexts[index]->promiseImageTexture(); |
191 | 0 | } |
192 | | |
193 | | void setMipLevels(const SkBitmap& baseLevel, std::unique_ptr<SkMipmap> mipLevels); |
194 | | |
195 | | /** Takes ownership of the plane data. */ |
196 | 0 | void setYUVPlanes(SkYUVAPixmaps yuvaPixmaps) { fYUVAPixmaps = std::move(yuvaPixmaps); } |
197 | | |
198 | | private: |
199 | | const int fIndex; // index in the 'fImageInfo' array |
200 | | const uint32_t fOriginalUniqueID; // original ID for deduping |
201 | | |
202 | | const SkImageInfo fImageInfo; // info for the overarching image |
203 | | |
204 | | // CPU-side cache of a normal SkImage's mipmap levels |
205 | | SkBitmap fBaseLevel; |
206 | | std::unique_ptr<SkMipmap> fMipLevels; |
207 | | |
208 | | // CPU-side cache of a YUV SkImage's contents |
209 | | SkYUVAPixmaps fYUVAPixmaps; |
210 | | |
211 | | // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image. |
212 | | sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVAInfo::kMaxPlanes]; |
213 | | }; |
214 | | |
215 | | struct DeserialImageProcContext { |
216 | | sk_sp<GrContextThreadSafeProxy> fThreadSafeProxy; |
217 | | DDLPromiseImageHelper* fHelper; |
218 | | }; |
219 | | |
220 | | static void CreateBETexturesForPromiseImage(GrDirectContext*, PromiseImageInfo*); |
221 | | static void DeleteBETexturesForPromiseImage(PromiseImageInfo*); |
222 | | |
223 | | static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn); |
224 | | |
225 | 0 | bool isValidID(int id) const { return id >= 0 && id < fImageInfo.size(); } |
226 | 0 | const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; } |
227 | | void uploadImage(GrDirectContext*, PromiseImageInfo*); |
228 | | |
229 | | // returns -1 if not found |
230 | | int findImage(SkImage* image) const; |
231 | | |
232 | | // returns -1 on failure |
233 | | int addImage(SkImage* image); |
234 | | |
235 | | // returns -1 on failure |
236 | | int findOrDefineImage(SkImage* image); |
237 | | |
238 | | SkYUVAPixmapInfo::SupportedDataTypes fSupportedYUVADataTypes; |
239 | | skia_private::TArray<PromiseImageInfo> fImageInfo; |
240 | | |
241 | | // TODO: review the use of 'fPromiseImages' - it doesn't seem useful/necessary |
242 | | skia_private::TArray<sk_sp<SkImage>> fPromiseImages; // All the promise images in the |
243 | | // reconstituted picture |
244 | | }; |
245 | | |
246 | | #endif |