blob: f8627aab36d55e3dc3d57d0e43f886ee4e414cf4 [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
Robert Phillips96601082018-05-29 16:13:26 -040011#include "GrBackendSurface.h"
Brian Salomon559c6172019-01-10 10:23:44 -050012#include "SkBitmap.h"
Robert Phillipse8e2bb12018-09-27 14:26:47 -040013#include "SkCachedData.h"
Brian Salomon559c6172019-01-10 10:23:44 -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:
50 DDLPromiseImageHelper() { }
Robert Phillipse8e2bb12018-09-27 14:26:47 -040051 ~DDLPromiseImageHelper();
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
56 void uploadAllToGPU(GrContext* context);
57
Brian Salomon559c6172019-01-10 10:23:44 -050058 // Change the backing store texture for half the images. (Must ensure all fulfilled images are
59 // released before calling this.).
60 void replaceEveryOtherPromiseTexture(GrContext*);
61
Robert Phillips96601082018-05-29 16:13:26 -040062 // reinflate a deflated SKP, replacing all the indices with promise images.
63 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
64 SkData* compressedPicture,
65 SkTArray<sk_sp<SkImage>>* promiseImages) const;
66
67 // Remove this class' refs on the PromiseImageCallbackContexts
68 void reset() { fImageInfo.reset(); }
69
70private:
Robert Phillipse8e2bb12018-09-27 14:26:47 -040071 // This class acts as a proxy for a GrBackendTexture that is part of an image.
Robert Phillips96601082018-05-29 16:13:26 -040072 // Whenever a promise image is created for the image, the promise image receives a ref to
Robert Phillipse8e2bb12018-09-27 14:26:47 -040073 // potentially several of these objects. Once all the promise images receive their done
74 // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
Robert Phillips96601082018-05-29 16:13:26 -040075 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
76 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
77 // it drops all of its refs (via "reset").
78 class PromiseImageCallbackContext : public SkRefCnt {
79 public:
80 PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
81
82 ~PromiseImageCallbackContext();
83
Brian Salomon559c6172019-01-10 10:23:44 -050084 void setBackendTexture(const GrBackendTexture& backendTexture);
85
86 void fulfill() {
87 SkASSERT(fUnreleasedFulfills >= 0);
88 ++fUnreleasedFulfills;
89 ++fTotalFulfills;
Robert Phillips96601082018-05-29 16:13:26 -040090 }
91
Brian Salomon559c6172019-01-10 10:23:44 -050092 void release() {
93 SkASSERT(fUnreleasedFulfills > 0);
94 --fUnreleasedFulfills;
95 ++fTotalReleases;
96 }
97
98 void done() {
99 ++fDoneCnt;
100 SkASSERT(fDoneCnt <= fNumImages);
101 }
102
103 void wasAddedToImage() { fNumImages++; }
104
105 SkPromiseImageTexture* promiseImageTexture() { return &fPromiseImageTexture; }
Robert Phillips96601082018-05-29 16:13:26 -0400106
107 private:
Brian Salomon559c6172019-01-10 10:23:44 -0500108 GrContext* fContext;
109 SkPromiseImageTexture fPromiseImageTexture;
110 int fNumImages = 0;
111 int fTotalFulfills = 0;
112 int fTotalReleases = 0;
113 int fUnreleasedFulfills = 0;
114 int fDoneCnt = 0;
Robert Phillips96601082018-05-29 16:13:26 -0400115
116 typedef SkRefCnt INHERITED;
117 };
118
119 // This is the information extracted into this class from the parsing of the skp file.
120 // Once it has all been uploaded to the GPU and distributed to the promise images, it
121 // is all dropped via "reset".
122 class PromiseImageInfo {
123 public:
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400124 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
125 : fIndex(index)
126 , fOriginalUniqueID(originalUniqueID)
127 , fImageInfo(ii) {
128 }
129 ~PromiseImageInfo() {}
130
131 int index() const { return fIndex; }
132 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
133 bool isYUV() const { return SkToBool(fYUVData.get()); }
134
135 int overallWidth() const { return fImageInfo.width(); }
136 int overallHeight() const { return fImageInfo.height(); }
137 SkColorType overallColorType() const { return fImageInfo.colorType(); }
138 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
139 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
140
141 SkYUVColorSpace yuvColorSpace() const {
142 SkASSERT(this->isYUV());
143 return fYUVColorSpace;
144 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400145 const SkYUVAIndex* yuvaIndices() const {
146 SkASSERT(this->isYUV());
147 return fYUVAIndices;
148 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400149 const SkPixmap& yuvPixmap(int index) const {
150 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400151 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400152 return fYUVPlanes[index];
153 }
154 const SkBitmap& normalBitmap() const {
155 SkASSERT(!this->isYUV());
156 return fBitmap;
157 }
158
159 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400160 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400161 fCallbackContexts[index] = callbackContext;
162 }
Brian Salomon559c6172019-01-10 10:23:44 -0500163 PromiseImageCallbackContext* callbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400164 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400165 return fCallbackContexts[index].get();
166 }
167 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400168 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400169 return fCallbackContexts[index];
170 }
171
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400172 const GrBackendTexture& backendTexture(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400173 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Brian Salomon559c6172019-01-10 10:23:44 -0500174 return fCallbackContexts[index]->promiseImageTexture()->backendTexture();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400175 }
176
177 void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
178
Jim Van Verth8f11e432018-10-18 14:36:59 -0400179 void setYUVData(sk_sp<SkCachedData> yuvData,
180 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
181 SkYUVColorSpace cs) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400182 fYUVData = yuvData;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400183 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400184 fYUVColorSpace = cs;
185 }
186 void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
187 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400188 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400189 fYUVPlanes[index].reset(ii, plane, widthBytes);
190 }
191
192 private:
193 const int fIndex; // index in the 'fImageInfo' array
194 const uint32_t fOriginalUniqueID; // original ID for deduping
195
196 const SkImageInfo fImageInfo; // info for the overarching image
197
198 // CPU-side cache of a normal SkImage's contents
199 SkBitmap fBitmap;
200
201 // CPU-side cache of a YUV SkImage's contents
202 sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
203 SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400204 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400205 SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400206
Jim Van Verthe24b5872018-10-29 16:26:02 -0400207 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
208 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400209 };
210
211 // This stack-based context allows each thread to re-inflate the image indices into
212 // promise images while still using the same GrBackendTexture.
213 struct PerRecorderContext {
214 SkDeferredDisplayListRecorder* fRecorder;
215 const DDLPromiseImageHelper* fHelper;
216 SkTArray<sk_sp<SkImage>>* fPromiseImages;
217 };
218
Brian Salomon559c6172019-01-10 10:23:44 -0500219 static SkPromiseImageTexture* PromiseImageFulfillProc(void* textureContext) {
Robert Phillips96601082018-05-29 16:13:26 -0400220 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomon559c6172019-01-10 10:23:44 -0500221 SkASSERT(callbackContext->promiseImageTexture()->isValid());
222 callbackContext->fulfill();
223 return callbackContext->promiseImageTexture();
Robert Phillips96601082018-05-29 16:13:26 -0400224 }
225
Brian Salomon559c6172019-01-10 10:23:44 -0500226 static void PromiseImageReleaseProc(void* textureContext,
227 const SkPromiseImageTexture* texture) {
Robert Phillips96601082018-05-29 16:13:26 -0400228 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomon559c6172019-01-10 10:23:44 -0500229 callbackContext->release();
230 SkASSERT(texture == callbackContext->promiseImageTexture());
231 SkASSERT(callbackContext->promiseImageTexture()->isValid());
Robert Phillips96601082018-05-29 16:13:26 -0400232 }
233
234 static void PromiseImageDoneProc(void* textureContext) {
235 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
Brian Salomon559c6172019-01-10 10:23:44 -0500236 callbackContext->done();
Robert Phillips96601082018-05-29 16:13:26 -0400237 callbackContext->unref();
238 }
239
240 static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
241
242 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
243 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
Brian Salomon559c6172019-01-10 10:23:44 -0500244 void uploadImage(GrContext*, PromiseImageInfo*);
Robert Phillips96601082018-05-29 16:13:26 -0400245
246 // returns -1 if not found
247 int findImage(SkImage* image) const;
248
249 // returns -1 on failure
250 int addImage(SkImage* image);
251
252 // returns -1 on failure
253 int findOrDefineImage(SkImage* image);
254
255 SkTArray<PromiseImageInfo> fImageInfo;
256};
257
258#endif