blob: 4a5bb23e8282c76379b19c772849a3c6729ce6f4 [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
8#ifndef PromiseImageHelper_DEFINED
9#define PromiseImageHelper_DEFINED
10
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkBitmap.h"
12#include "include/core/SkDeferredDisplayListRecorder.h"
13#include "include/core/SkPromiseImageTexture.h"
14#include "include/core/SkYUVAIndex.h"
15#include "include/core/SkYUVASizeInfo.h"
16#include "include/gpu/GrBackendSurface.h"
17#include "include/private/SkTArray.h"
18#include "src/core/SkCachedData.h"
19#include "src/core/SkTLazy.h"
Robert Phillips96601082018-05-29 16:13:26 -040020
21class GrContext;
Robert Phillips96601082018-05-29 16:13:26 -040022class SkImage;
Robert Phillipsf95e2f42020-04-17 16:20:55 -040023class SkMipMap;
Robert Phillips96601082018-05-29 16:13:26 -040024class SkPicture;
Jim Van Verth8f11e432018-10-18 14:36:59 -040025struct SkYUVAIndex;
Robert Phillips96601082018-05-29 16:13:26 -040026
Robert Phillips11c67672020-04-23 15:10:03 -040027// 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").
34class PromiseImageCallbackContext : public SkRefCnt {
35public:
36 PromiseImageCallbackContext(GrContext* context, GrBackendFormat backendFormat)
37 : fContext(context)
38 , fBackendFormat(backendFormat) {}
39
40 ~PromiseImageCallbackContext();
41
42 const GrBackendFormat& backendFormat() const { return fBackendFormat; }
43
44 void setBackendTexture(const GrBackendTexture& backendTexture);
45
46 void destroyBackendTexture() {
47 SkASSERT(!fPromiseImageTexture || fPromiseImageTexture->unique());
48
49 if (fPromiseImageTexture) {
50 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
51 }
52 fPromiseImageTexture = nullptr;
53 }
54
55 sk_sp<SkPromiseImageTexture> fulfill() {
56 SkASSERT(fUnreleasedFulfills >= 0);
57 ++fUnreleasedFulfills;
58 ++fTotalFulfills;
59 return fPromiseImageTexture;
60 }
61
62 void release() {
63 SkASSERT(fUnreleasedFulfills > 0);
64 --fUnreleasedFulfills;
65 ++fTotalReleases;
66 }
67
68 void done() {
69 ++fDoneCnt;
70 SkASSERT(fDoneCnt <= fNumImages);
71 }
72
73 void wasAddedToImage() { fNumImages++; }
74
75 const SkPromiseImageTexture* promiseImageTexture() const {
76 return fPromiseImageTexture.get();
77 }
78
79 static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
80 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
81 return callbackContext->fulfill();
82 }
83
84 static void PromiseImageReleaseProc(void* textureContext) {
85 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
86 callbackContext->release();
87 }
88
89 static void PromiseImageDoneProc(void* textureContext) {
90 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
91 callbackContext->done();
92 callbackContext->unref();
93 }
94
95private:
96 GrContext* fContext;
97 GrBackendFormat fBackendFormat;
98 sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
99 int fNumImages = 0;
100 int fTotalFulfills = 0;
101 int fTotalReleases = 0;
102 int fUnreleasedFulfills = 0;
103 int fDoneCnt = 0;
104
105 typedef SkRefCnt INHERITED;
106};
107
Robert Phillips96601082018-05-29 16:13:26 -0400108// This class consolidates tracking & extraction of the original image data from an skp,
109// the upload of said data to the GPU and the fulfillment of promise images.
110//
111// The way this works is:
112// the original skp is converted to SkData and all its image info is extracted into this
113// class and only indices into this class are left in the SkData (via deflateSKP)
114//
115// Prior to replaying in threads, all the images stored in this class are uploaded to the
116// gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
117//
118// Each thread reinflates the SkData into an SkPicture replacing all the indices w/
119// promise images (all using the same GrBackendTexture and getting a ref to the
120// appropriate PromiseImageCallbackContext) (via reinflateSKP).
121//
122// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
123//
124// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400125// are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
Robert Phillips96601082018-05-29 16:13:26 -0400126// from VRAM
127//
128// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
129// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
130class DDLPromiseImageHelper {
131public:
Brian Salomon7d88f312019-02-28 10:03:03 -0500132 DDLPromiseImageHelper() = default;
133 ~DDLPromiseImageHelper() = default;
Robert Phillips96601082018-05-29 16:13:26 -0400134
135 // Convert the SkPicture into SkData replacing all the SkImages with an index.
136 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
137
Robert Phillips923181b2020-02-14 12:36:37 -0500138 void createCallbackContexts(GrContext*);
139
140 void uploadAllToGPU(SkTaskGroup*, GrContext*);
Robert Phillips19f466d2020-02-26 10:27:07 -0500141 void deleteAllFromGPU(SkTaskGroup*, GrContext*);
Robert Phillips96601082018-05-29 16:13:26 -0400142
143 // reinflate a deflated SKP, replacing all the indices with promise images.
144 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
145 SkData* compressedPicture,
146 SkTArray<sk_sp<SkImage>>* promiseImages) const;
147
148 // Remove this class' refs on the PromiseImageCallbackContexts
149 void reset() { fImageInfo.reset(); }
150
151private:
Robert Phillips96601082018-05-29 16:13:26 -0400152 // This is the information extracted into this class from the parsing of the skp file.
153 // Once it has all been uploaded to the GPU and distributed to the promise images, it
154 // is all dropped via "reset".
155 class PromiseImageInfo {
156 public:
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400157 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii);
158 PromiseImageInfo(PromiseImageInfo&& other);
159 ~PromiseImageInfo();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400160
161 int index() const { return fIndex; }
162 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
163 bool isYUV() const { return SkToBool(fYUVData.get()); }
164
165 int overallWidth() const { return fImageInfo.width(); }
166 int overallHeight() const { return fImageInfo.height(); }
167 SkColorType overallColorType() const { return fImageInfo.colorType(); }
168 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
169 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
170
171 SkYUVColorSpace yuvColorSpace() const {
172 SkASSERT(this->isYUV());
173 return fYUVColorSpace;
174 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400175 const SkYUVAIndex* yuvaIndices() const {
176 SkASSERT(this->isYUV());
177 return fYUVAIndices;
178 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400179 const SkPixmap& yuvPixmap(int index) const {
180 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400181 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400182 return fYUVPlanes[index];
183 }
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400184
185 const SkBitmap& baseLevel() const {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400186 SkASSERT(!this->isYUV());
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400187 return fBaseLevel;
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400188 }
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400189 // This returns an array of all the available mipLevels - suitable for passing into
190 // createBackendTexture.
191 const std::unique_ptr<SkPixmap[]> normalMipLevels() const;
192 int numMipLevels() const;
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400193
194 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400195 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400196 fCallbackContexts[index] = callbackContext;
197 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500198 PromiseImageCallbackContext* callbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400199 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400200 return fCallbackContexts[index].get();
201 }
202 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400203 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400204 return fCallbackContexts[index];
205 }
206
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400207 GrMipMapped mipMapped(int index) const {
208 if (this->isYUV()) {
209 return GrMipMapped::kNo;
210 }
211 return fMipLevels ? GrMipMapped::kYes : GrMipMapped::kNo;
212 }
Robert Phillips923181b2020-02-14 12:36:37 -0500213 const GrBackendFormat& backendFormat(int index) const {
214 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
215 return fCallbackContexts[index]->backendFormat();
216 }
Brian Salomon3f4cd772019-01-11 16:03:19 -0500217 const SkPromiseImageTexture* promiseTexture(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400218 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Brian Salomon3f4cd772019-01-11 16:03:19 -0500219 return fCallbackContexts[index]->promiseImageTexture();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400220 }
221
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400222 void setMipLevels(const SkBitmap& baseLevel, std::unique_ptr<SkMipMap> mipLevels);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400223
Jim Van Verth8f11e432018-10-18 14:36:59 -0400224 void setYUVData(sk_sp<SkCachedData> yuvData,
225 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
226 SkYUVColorSpace cs) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400227 fYUVData = yuvData;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400228 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400229 fYUVColorSpace = cs;
230 }
231 void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
232 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400233 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400234 fYUVPlanes[index].reset(ii, plane, widthBytes);
235 }
236
237 private:
238 const int fIndex; // index in the 'fImageInfo' array
239 const uint32_t fOriginalUniqueID; // original ID for deduping
240
241 const SkImageInfo fImageInfo; // info for the overarching image
242
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400243 // CPU-side cache of a normal SkImage's mipmap levels
244 SkBitmap fBaseLevel;
245 std::unique_ptr<SkMipMap> fMipLevels;
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400246
247 // CPU-side cache of a YUV SkImage's contents
248 sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
249 SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400250 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400251 SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400252
Jim Van Verthe24b5872018-10-29 16:26:02 -0400253 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
254 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400255 };
256
257 // This stack-based context allows each thread to re-inflate the image indices into
258 // promise images while still using the same GrBackendTexture.
259 struct PerRecorderContext {
260 SkDeferredDisplayListRecorder* fRecorder;
261 const DDLPromiseImageHelper* fHelper;
262 SkTArray<sk_sp<SkImage>>* fPromiseImages;
263 };
264
Robert Phillips923181b2020-02-14 12:36:37 -0500265 static void CreateBETexturesForPromiseImage(GrContext*, PromiseImageInfo*);
Robert Phillips19f466d2020-02-26 10:27:07 -0500266 static void DeleteBETexturesForPromiseImage(GrContext*, PromiseImageInfo*);
Robert Phillips923181b2020-02-14 12:36:37 -0500267
Robert Phillips923181b2020-02-14 12:36:37 -0500268 static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn);
Robert Phillips96601082018-05-29 16:13:26 -0400269
270 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
271 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500272 void uploadImage(GrContext*, PromiseImageInfo*);
Robert Phillips96601082018-05-29 16:13:26 -0400273
274 // returns -1 if not found
275 int findImage(SkImage* image) const;
276
277 // returns -1 on failure
278 int addImage(SkImage* image);
279
280 // returns -1 on failure
281 int findOrDefineImage(SkImage* image);
282
283 SkTArray<PromiseImageInfo> fImageInfo;
284};
285
286#endif