blob: 1a0b043e64458b6d2305939b061d461562d29242 [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
Brian Salomon426ba462019-01-10 16:33:06 +000011#include "GrBackendSurface.h"
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050012#include "SkBitmap.h"
Brian Salomon426ba462019-01-10 16:33:06 +000013#include "SkCachedData.h"
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050014#include "SkDeferredDisplayListRecorder.h"
15#include "SkPromiseImageTexture.h"
16#include "SkTArray.h"
17#include "SkTLazy.h"
Jim Van Verth8f11e432018-10-18 14:36:59 -040018#include "SkYUVAIndex.h"
Jim Van Verthe24b5872018-10-29 16:26:02 -040019#include "SkYUVASizeInfo.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 Salomonf55e8d52019-01-30 17:28:20 -050050 using DelayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback;
51 DDLPromiseImageHelper(DelayReleaseCallback delayReleaseCallback = DelayReleaseCallback::kNo)
52 : fDelayReleaseCallback(delayReleaseCallback) {}
Robert Phillipse8e2bb12018-09-27 14:26:47 -040053 ~DDLPromiseImageHelper();
Robert Phillips96601082018-05-29 16:13:26 -040054
55 // Convert the SkPicture into SkData replacing all the SkImages with an index.
56 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
57
58 void uploadAllToGPU(GrContext* context);
59
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050060 // Change the backing store texture for half the images. (Must ensure all fulfilled images are
61 // released before calling this.).
62 void replaceEveryOtherPromiseTexture(GrContext*);
63
Robert Phillips96601082018-05-29 16:13:26 -040064 // reinflate a deflated SKP, replacing all the indices with promise images.
65 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
66 SkData* compressedPicture,
67 SkTArray<sk_sp<SkImage>>* promiseImages) const;
68
69 // Remove this class' refs on the PromiseImageCallbackContexts
70 void reset() { fImageInfo.reset(); }
71
72private:
Robert Phillipse8e2bb12018-09-27 14:26:47 -040073 // This class acts as a proxy for a GrBackendTexture that is part of an image.
Robert Phillips96601082018-05-29 16:13:26 -040074 // Whenever a promise image is created for the image, the promise image receives a ref to
Robert Phillipse8e2bb12018-09-27 14:26:47 -040075 // potentially several of these objects. Once all the promise images receive their done
76 // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
Robert Phillips96601082018-05-29 16:13:26 -040077 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
78 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
79 // it drops all of its refs (via "reset").
80 class PromiseImageCallbackContext : public SkRefCnt {
81 public:
82 PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
83
84 ~PromiseImageCallbackContext();
85
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050086 void setBackendTexture(const GrBackendTexture& backendTexture);
87
Brian Salomon3f4cd772019-01-11 16:03:19 -050088 sk_sp<SkPromiseImageTexture> fulfill() {
89 SkASSERT(fPromiseImageTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050090 SkASSERT(fUnreleasedFulfills >= 0);
91 ++fUnreleasedFulfills;
92 ++fTotalFulfills;
Brian Salomon3f4cd772019-01-11 16:03:19 -050093 return fPromiseImageTexture;
Robert Phillips96601082018-05-29 16:13:26 -040094 }
95
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050096 void release() {
97 SkASSERT(fUnreleasedFulfills > 0);
98 --fUnreleasedFulfills;
99 ++fTotalReleases;
100 }
101
102 void done() {
103 ++fDoneCnt;
104 SkASSERT(fDoneCnt <= fNumImages);
105 }
106
107 void wasAddedToImage() { fNumImages++; }
108
Brian Salomon3f4cd772019-01-11 16:03:19 -0500109 const SkPromiseImageTexture* promiseImageTexture() const {
110 return fPromiseImageTexture.get();
111 }
Robert Phillips96601082018-05-29 16:13:26 -0400112
113 private:
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500114 GrContext* fContext;
Brian Salomon3f4cd772019-01-11 16:03:19 -0500115 sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500116 int fNumImages = 0;
117 int fTotalFulfills = 0;
118 int fTotalReleases = 0;
119 int fUnreleasedFulfills = 0;
120 int fDoneCnt = 0;
Robert Phillips96601082018-05-29 16:13:26 -0400121
122 typedef SkRefCnt INHERITED;
123 };
124
125 // This is the information extracted into this class from the parsing of the skp file.
126 // Once it has all been uploaded to the GPU and distributed to the promise images, it
127 // is all dropped via "reset".
128 class PromiseImageInfo {
129 public:
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400130 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
131 : fIndex(index)
132 , fOriginalUniqueID(originalUniqueID)
133 , fImageInfo(ii) {
134 }
135 ~PromiseImageInfo() {}
136
137 int index() const { return fIndex; }
138 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
139 bool isYUV() const { return SkToBool(fYUVData.get()); }
140
141 int overallWidth() const { return fImageInfo.width(); }
142 int overallHeight() const { return fImageInfo.height(); }
143 SkColorType overallColorType() const { return fImageInfo.colorType(); }
144 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
145 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
146
147 SkYUVColorSpace yuvColorSpace() const {
148 SkASSERT(this->isYUV());
149 return fYUVColorSpace;
150 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400151 const SkYUVAIndex* yuvaIndices() const {
152 SkASSERT(this->isYUV());
153 return fYUVAIndices;
154 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400155 const SkPixmap& yuvPixmap(int index) const {
156 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400157 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400158 return fYUVPlanes[index];
159 }
160 const SkBitmap& normalBitmap() const {
161 SkASSERT(!this->isYUV());
162 return fBitmap;
163 }
164
165 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400166 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400167 fCallbackContexts[index] = callbackContext;
168 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500169 PromiseImageCallbackContext* callbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400170 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400171 return fCallbackContexts[index].get();
172 }
173 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400174 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400175 return fCallbackContexts[index];
176 }
177
Brian Salomon3f4cd772019-01-11 16:03:19 -0500178 const SkPromiseImageTexture* promiseTexture(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400179 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Brian Salomon3f4cd772019-01-11 16:03:19 -0500180 return fCallbackContexts[index]->promiseImageTexture();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400181 }
182
183 void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
184
Jim Van Verth8f11e432018-10-18 14:36:59 -0400185 void setYUVData(sk_sp<SkCachedData> yuvData,
186 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
187 SkYUVColorSpace cs) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400188 fYUVData = yuvData;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400189 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400190 fYUVColorSpace = cs;
191 }
192 void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
193 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400194 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400195 fYUVPlanes[index].reset(ii, plane, widthBytes);
196 }
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 contents
205 SkBitmap fBitmap;
206
207 // CPU-side cache of a YUV SkImage's contents
208 sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
209 SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400210 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400211 SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400212
Jim Van Verthe24b5872018-10-29 16:26:02 -0400213 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
214 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400215 };
216
217 // This stack-based context allows each thread to re-inflate the image indices into
218 // promise images while still using the same GrBackendTexture.
219 struct PerRecorderContext {
220 SkDeferredDisplayListRecorder* fRecorder;
221 const DDLPromiseImageHelper* fHelper;
222 SkTArray<sk_sp<SkImage>>* fPromiseImages;
223 };
224
Brian Salomon3f4cd772019-01-11 16:03:19 -0500225 static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
Robert Phillips96601082018-05-29 16:13:26 -0400226 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomon3f4cd772019-01-11 16:03:19 -0500227 return callbackContext->fulfill();
Robert Phillips96601082018-05-29 16:13:26 -0400228 }
229
Brian Salomon3f4cd772019-01-11 16:03:19 -0500230 static void PromiseImageReleaseProc(void* textureContext) {
Robert Phillips96601082018-05-29 16:13:26 -0400231 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500232 callbackContext->release();
Robert Phillips96601082018-05-29 16:13:26 -0400233 }
234
235 static void PromiseImageDoneProc(void* textureContext) {
236 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500237 callbackContext->done();
Robert Phillips96601082018-05-29 16:13:26 -0400238 callbackContext->unref();
239 }
240
241 static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
242
243 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
244 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500245 void uploadImage(GrContext*, PromiseImageInfo*);
Robert Phillips96601082018-05-29 16:13:26 -0400246
247 // returns -1 if not found
248 int findImage(SkImage* image) const;
249
250 // returns -1 on failure
251 int addImage(SkImage* image);
252
253 // returns -1 on failure
254 int findOrDefineImage(SkImage* image);
255
Brian Salomonf55e8d52019-01-30 17:28:20 -0500256 DelayReleaseCallback fDelayReleaseCallback;
Robert Phillips96601082018-05-29 16:13:26 -0400257 SkTArray<PromiseImageInfo> fImageInfo;
258};
259
260#endif