blob: f8e8dd609367f8c036300297cec92688883fab35 [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;
23class SkPicture;
Jim Van Verth8f11e432018-10-18 14:36:59 -040024struct SkYUVAIndex;
Robert Phillips96601082018-05-29 16:13:26 -040025
26// This class consolidates tracking & extraction of the original image data from an skp,
27// the upload of said data to the GPU and the fulfillment of promise images.
28//
29// The way this works is:
30// the original skp is converted to SkData and all its image info is extracted into this
31// class and only indices into this class are left in the SkData (via deflateSKP)
32//
33// Prior to replaying in threads, all the images stored in this class are uploaded to the
34// gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
35//
36// Each thread reinflates the SkData into an SkPicture replacing all the indices w/
37// promise images (all using the same GrBackendTexture and getting a ref to the
38// appropriate PromiseImageCallbackContext) (via reinflateSKP).
39//
40// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
41//
42// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
Robert Phillipse8e2bb12018-09-27 14:26:47 -040043// are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
Robert Phillips96601082018-05-29 16:13:26 -040044// from VRAM
45//
46// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
47// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
48class DDLPromiseImageHelper {
49public:
Brian Salomon7d88f312019-02-28 10:03:03 -050050 DDLPromiseImageHelper() = default;
51 ~DDLPromiseImageHelper() = default;
Robert Phillips96601082018-05-29 16:13:26 -040052
53 // Convert the SkPicture into SkData replacing all the SkImages with an index.
54 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
55
Robert Phillips923181b2020-02-14 12:36:37 -050056 void createCallbackContexts(GrContext*);
57
58 void uploadAllToGPU(SkTaskGroup*, GrContext*);
Robert Phillips19f466d2020-02-26 10:27:07 -050059 void deleteAllFromGPU(SkTaskGroup*, GrContext*);
Robert Phillips96601082018-05-29 16:13:26 -040060
61 // reinflate a deflated SKP, replacing all the indices with promise images.
62 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
63 SkData* compressedPicture,
64 SkTArray<sk_sp<SkImage>>* promiseImages) const;
65
66 // Remove this class' refs on the PromiseImageCallbackContexts
67 void reset() { fImageInfo.reset(); }
68
69private:
Robert Phillipse8e2bb12018-09-27 14:26:47 -040070 // This class acts as a proxy for a GrBackendTexture that is part of an image.
Robert Phillips96601082018-05-29 16:13:26 -040071 // Whenever a promise image is created for the image, the promise image receives a ref to
Robert Phillipse8e2bb12018-09-27 14:26:47 -040072 // potentially several of these objects. Once all the promise images receive their done
73 // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
Robert Phillips96601082018-05-29 16:13:26 -040074 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
75 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
76 // it drops all of its refs (via "reset").
77 class PromiseImageCallbackContext : public SkRefCnt {
78 public:
Robert Phillips923181b2020-02-14 12:36:37 -050079 PromiseImageCallbackContext(GrContext* context, GrBackendFormat backendFormat)
80 : fContext(context)
81 , fBackendFormat(backendFormat) {}
Robert Phillips96601082018-05-29 16:13:26 -040082
83 ~PromiseImageCallbackContext();
84
Robert Phillips923181b2020-02-14 12:36:37 -050085 const GrBackendFormat& backendFormat() const { return fBackendFormat; }
86
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050087 void setBackendTexture(const GrBackendTexture& backendTexture);
88
Robert Phillips19f466d2020-02-26 10:27:07 -050089 void destroyBackendTexture() {
90 SkASSERT(fPromiseImageTexture && fPromiseImageTexture->unique());
91 fPromiseImageTexture = nullptr;
92 }
93
Brian Salomon3f4cd772019-01-11 16:03:19 -050094 sk_sp<SkPromiseImageTexture> fulfill() {
95 SkASSERT(fPromiseImageTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050096 SkASSERT(fUnreleasedFulfills >= 0);
97 ++fUnreleasedFulfills;
98 ++fTotalFulfills;
Brian Salomon3f4cd772019-01-11 16:03:19 -050099 return fPromiseImageTexture;
Robert Phillips96601082018-05-29 16:13:26 -0400100 }
101
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500102 void release() {
103 SkASSERT(fUnreleasedFulfills > 0);
104 --fUnreleasedFulfills;
105 ++fTotalReleases;
106 }
107
108 void done() {
109 ++fDoneCnt;
110 SkASSERT(fDoneCnt <= fNumImages);
111 }
112
113 void wasAddedToImage() { fNumImages++; }
114
Brian Salomon3f4cd772019-01-11 16:03:19 -0500115 const SkPromiseImageTexture* promiseImageTexture() const {
Robert Phillips923181b2020-02-14 12:36:37 -0500116 return fPromiseImageTexture.get();
Brian Salomon3f4cd772019-01-11 16:03:19 -0500117 }
Robert Phillips96601082018-05-29 16:13:26 -0400118
119 private:
Robert Phillips923181b2020-02-14 12:36:37 -0500120 GrContext* fContext;
121 GrBackendFormat fBackendFormat;
Brian Salomon3f4cd772019-01-11 16:03:19 -0500122 sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
Robert Phillips923181b2020-02-14 12:36:37 -0500123 int fNumImages = 0;
124 int fTotalFulfills = 0;
125 int fTotalReleases = 0;
126 int fUnreleasedFulfills = 0;
127 int fDoneCnt = 0;
Robert Phillips96601082018-05-29 16:13:26 -0400128
129 typedef SkRefCnt INHERITED;
130 };
131
132 // This is the information extracted into this class from the parsing of the skp file.
133 // Once it has all been uploaded to the GPU and distributed to the promise images, it
134 // is all dropped via "reset".
135 class PromiseImageInfo {
136 public:
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400137 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
138 : fIndex(index)
139 , fOriginalUniqueID(originalUniqueID)
140 , fImageInfo(ii) {
141 }
142 ~PromiseImageInfo() {}
143
144 int index() const { return fIndex; }
145 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
146 bool isYUV() const { return SkToBool(fYUVData.get()); }
147
148 int overallWidth() const { return fImageInfo.width(); }
149 int overallHeight() const { return fImageInfo.height(); }
150 SkColorType overallColorType() const { return fImageInfo.colorType(); }
151 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
152 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
153
154 SkYUVColorSpace yuvColorSpace() const {
155 SkASSERT(this->isYUV());
156 return fYUVColorSpace;
157 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400158 const SkYUVAIndex* yuvaIndices() const {
159 SkASSERT(this->isYUV());
160 return fYUVAIndices;
161 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400162 const SkPixmap& yuvPixmap(int index) const {
163 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400164 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400165 return fYUVPlanes[index];
166 }
167 const SkBitmap& normalBitmap() const {
168 SkASSERT(!this->isYUV());
169 return fBitmap;
170 }
171
172 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400173 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400174 fCallbackContexts[index] = callbackContext;
175 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500176 PromiseImageCallbackContext* callbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400177 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400178 return fCallbackContexts[index].get();
179 }
180 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400181 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400182 return fCallbackContexts[index];
183 }
184
Robert Phillips923181b2020-02-14 12:36:37 -0500185 const GrBackendFormat& backendFormat(int index) const {
186 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
187 return fCallbackContexts[index]->backendFormat();
188 }
Brian Salomon3f4cd772019-01-11 16:03:19 -0500189 const SkPromiseImageTexture* promiseTexture(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400190 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Brian Salomon3f4cd772019-01-11 16:03:19 -0500191 return fCallbackContexts[index]->promiseImageTexture();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400192 }
193
194 void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
195
Jim Van Verth8f11e432018-10-18 14:36:59 -0400196 void setYUVData(sk_sp<SkCachedData> yuvData,
197 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
198 SkYUVColorSpace cs) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400199 fYUVData = yuvData;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400200 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400201 fYUVColorSpace = cs;
202 }
203 void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
204 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400205 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400206 fYUVPlanes[index].reset(ii, plane, widthBytes);
207 }
208
209 private:
210 const int fIndex; // index in the 'fImageInfo' array
211 const uint32_t fOriginalUniqueID; // original ID for deduping
212
213 const SkImageInfo fImageInfo; // info for the overarching image
214
215 // CPU-side cache of a normal SkImage's contents
216 SkBitmap fBitmap;
217
218 // CPU-side cache of a YUV SkImage's contents
219 sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
220 SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400221 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400222 SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400223
Jim Van Verthe24b5872018-10-29 16:26:02 -0400224 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
225 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400226 };
227
228 // This stack-based context allows each thread to re-inflate the image indices into
229 // promise images while still using the same GrBackendTexture.
230 struct PerRecorderContext {
231 SkDeferredDisplayListRecorder* fRecorder;
232 const DDLPromiseImageHelper* fHelper;
233 SkTArray<sk_sp<SkImage>>* fPromiseImages;
234 };
235
Robert Phillips923181b2020-02-14 12:36:37 -0500236 static void CreateBETexturesForPromiseImage(GrContext*, PromiseImageInfo*);
Robert Phillips19f466d2020-02-26 10:27:07 -0500237 static void DeleteBETexturesForPromiseImage(GrContext*, PromiseImageInfo*);
Robert Phillips923181b2020-02-14 12:36:37 -0500238
Brian Salomon3f4cd772019-01-11 16:03:19 -0500239 static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
Robert Phillips96601082018-05-29 16:13:26 -0400240 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomon3f4cd772019-01-11 16:03:19 -0500241 return callbackContext->fulfill();
Robert Phillips96601082018-05-29 16:13:26 -0400242 }
243
Brian Salomon3f4cd772019-01-11 16:03:19 -0500244 static void PromiseImageReleaseProc(void* textureContext) {
Robert Phillips96601082018-05-29 16:13:26 -0400245 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500246 callbackContext->release();
Robert Phillips96601082018-05-29 16:13:26 -0400247 }
248
249 static void PromiseImageDoneProc(void* textureContext) {
250 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500251 callbackContext->done();
Robert Phillips96601082018-05-29 16:13:26 -0400252 callbackContext->unref();
253 }
254
Robert Phillips923181b2020-02-14 12:36:37 -0500255 static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn);
Robert Phillips96601082018-05-29 16:13:26 -0400256
257 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
258 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500259 void uploadImage(GrContext*, PromiseImageInfo*);
Robert Phillips96601082018-05-29 16:13:26 -0400260
261 // returns -1 if not found
262 int findImage(SkImage* image) const;
263
264 // returns -1 on failure
265 int addImage(SkImage* image);
266
267 // returns -1 on failure
268 int findOrDefineImage(SkImage* image);
269
270 SkTArray<PromiseImageInfo> fImageInfo;
271};
272
273#endif