blob: 7a636ce15b7996bfed77c9ba07aa93a1b49869ad [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
11#include "SkBitmap.h"
12#include "SkTArray.h"
13
Robert Phillips96601082018-05-29 16:13:26 -040014#include "GrBackendSurface.h"
Robert Phillipse8e2bb12018-09-27 14:26:47 -040015#include "SkCachedData.h"
Jim Van Verth8f11e432018-10-18 14:36:59 -040016#include "SkYUVAIndex.h"
Jim Van Verthe24b5872018-10-29 16:26:02 -040017#include "SkYUVASizeInfo.h"
Robert Phillips96601082018-05-29 16:13:26 -040018
19class GrContext;
20class SkDeferredDisplayListRecorder;
21class SkImage;
22class SkPicture;
Jim Van Verth8f11e432018-10-18 14:36:59 -040023struct SkYUVAIndex;
Robert Phillips96601082018-05-29 16:13:26 -040024
25// This class consolidates tracking & extraction of the original image data from an skp,
26// the upload of said data to the GPU and the fulfillment of promise images.
27//
28// The way this works is:
29// the original skp is converted to SkData and all its image info is extracted into this
30// class and only indices into this class are left in the SkData (via deflateSKP)
31//
32// Prior to replaying in threads, all the images stored in this class are uploaded to the
33// gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
34//
35// Each thread reinflates the SkData into an SkPicture replacing all the indices w/
36// promise images (all using the same GrBackendTexture and getting a ref to the
37// appropriate PromiseImageCallbackContext) (via reinflateSKP).
38//
39// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
40//
41// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
Robert Phillipse8e2bb12018-09-27 14:26:47 -040042// are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
Robert Phillips96601082018-05-29 16:13:26 -040043// from VRAM
44//
45// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
46// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
47class DDLPromiseImageHelper {
48public:
49 DDLPromiseImageHelper() { }
Robert Phillipse8e2bb12018-09-27 14:26:47 -040050 ~DDLPromiseImageHelper();
Robert Phillips96601082018-05-29 16:13:26 -040051
52 // Convert the SkPicture into SkData replacing all the SkImages with an index.
53 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
54
55 void uploadAllToGPU(GrContext* context);
56
57 // reinflate a deflated SKP, replacing all the indices with promise images.
58 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
59 SkData* compressedPicture,
60 SkTArray<sk_sp<SkImage>>* promiseImages) const;
61
62 // Remove this class' refs on the PromiseImageCallbackContexts
63 void reset() { fImageInfo.reset(); }
64
65private:
Robert Phillipse8e2bb12018-09-27 14:26:47 -040066 // This class acts as a proxy for a GrBackendTexture that is part of an image.
Robert Phillips96601082018-05-29 16:13:26 -040067 // Whenever a promise image is created for the image, the promise image receives a ref to
Robert Phillipse8e2bb12018-09-27 14:26:47 -040068 // potentially several of these objects. Once all the promise images receive their done
69 // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
Robert Phillips96601082018-05-29 16:13:26 -040070 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
71 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
72 // it drops all of its refs (via "reset").
73 class PromiseImageCallbackContext : public SkRefCnt {
74 public:
75 PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
76
77 ~PromiseImageCallbackContext();
78
79 void setBackendTexture(const GrBackendTexture& backendTexture) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040080 SkASSERT(!fBackendTexture.isValid());
Robert Phillips96601082018-05-29 16:13:26 -040081 fBackendTexture = backendTexture;
82 }
83
84 const GrBackendTexture& backendTexture() const { return fBackendTexture; }
85
86 private:
87 GrContext* fContext;
88 GrBackendTexture fBackendTexture;
89
90 typedef SkRefCnt INHERITED;
91 };
92
93 // This is the information extracted into this class from the parsing of the skp file.
94 // Once it has all been uploaded to the GPU and distributed to the promise images, it
95 // is all dropped via "reset".
96 class PromiseImageInfo {
97 public:
Robert Phillipse8e2bb12018-09-27 14:26:47 -040098 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
99 : fIndex(index)
100 , fOriginalUniqueID(originalUniqueID)
101 , fImageInfo(ii) {
102 }
103 ~PromiseImageInfo() {}
104
105 int index() const { return fIndex; }
106 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
107 bool isYUV() const { return SkToBool(fYUVData.get()); }
108
109 int overallWidth() const { return fImageInfo.width(); }
110 int overallHeight() const { return fImageInfo.height(); }
111 SkColorType overallColorType() const { return fImageInfo.colorType(); }
112 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
113 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
114
115 SkYUVColorSpace yuvColorSpace() const {
116 SkASSERT(this->isYUV());
117 return fYUVColorSpace;
118 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400119 const SkYUVAIndex* yuvaIndices() const {
120 SkASSERT(this->isYUV());
121 return fYUVAIndices;
122 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400123 const SkPixmap& yuvPixmap(int index) const {
124 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400125 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400126 return fYUVPlanes[index];
127 }
128 const SkBitmap& normalBitmap() const {
129 SkASSERT(!this->isYUV());
130 return fBitmap;
131 }
132
133 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400134 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400135 fCallbackContexts[index] = callbackContext;
136 }
137 PromiseImageCallbackContext* callbackContext(int index) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400138 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400139 return fCallbackContexts[index].get();
140 }
141 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400142 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400143 return fCallbackContexts[index];
144 }
145
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400146 const GrBackendTexture& backendTexture(int index) const {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400147 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400148 return fCallbackContexts[index]->backendTexture();
149 }
150
151 void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
152
Jim Van Verth8f11e432018-10-18 14:36:59 -0400153 void setYUVData(sk_sp<SkCachedData> yuvData,
154 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
155 SkYUVColorSpace cs) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400156 fYUVData = yuvData;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400157 memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400158 fYUVColorSpace = cs;
159 }
160 void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
161 SkASSERT(this->isYUV());
Jim Van Verthe24b5872018-10-29 16:26:02 -0400162 SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400163 fYUVPlanes[index].reset(ii, plane, widthBytes);
164 }
165
166 private:
167 const int fIndex; // index in the 'fImageInfo' array
168 const uint32_t fOriginalUniqueID; // original ID for deduping
169
170 const SkImageInfo fImageInfo; // info for the overarching image
171
172 // CPU-side cache of a normal SkImage's contents
173 SkBitmap fBitmap;
174
175 // CPU-side cache of a YUV SkImage's contents
176 sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
177 SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400178 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
Jim Van Verthe24b5872018-10-29 16:26:02 -0400179 SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400180
Jim Van Verthe24b5872018-10-29 16:26:02 -0400181 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
182 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400183 };
184
185 // This stack-based context allows each thread to re-inflate the image indices into
186 // promise images while still using the same GrBackendTexture.
187 struct PerRecorderContext {
188 SkDeferredDisplayListRecorder* fRecorder;
189 const DDLPromiseImageHelper* fHelper;
190 SkTArray<sk_sp<SkImage>>* fPromiseImages;
191 };
192
193 static void PromiseImageFulfillProc(void* textureContext, GrBackendTexture* outTexture) {
194 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
195 SkASSERT(callbackContext->backendTexture().isValid());
196 *outTexture = callbackContext->backendTexture();
197 }
198
199 static void PromiseImageReleaseProc(void* textureContext) {
200#ifdef SK_DEBUG
201 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
202 SkASSERT(callbackContext->backendTexture().isValid());
203#endif
204 }
205
206 static void PromiseImageDoneProc(void* textureContext) {
207 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
208 callbackContext->unref();
209 }
210
211 static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
212
213 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
214 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
215
216 // returns -1 if not found
217 int findImage(SkImage* image) const;
218
219 // returns -1 on failure
220 int addImage(SkImage* image);
221
222 // returns -1 on failure
223 int findOrDefineImage(SkImage* image);
224
225 SkTArray<PromiseImageInfo> fImageInfo;
226};
227
228#endif