blob: 2fde554ddd18d8d73ed7156582df6af848d999fd [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"
Brian Salomonbe0e42c2020-08-27 11:00:04 -040015#include "include/core/SkYUVAPixmaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkYUVASizeInfo.h"
17#include "include/gpu/GrBackendSurface.h"
18#include "include/private/SkTArray.h"
19#include "src/core/SkCachedData.h"
20#include "src/core/SkTLazy.h"
Robert Phillips96601082018-05-29 16:13:26 -040021
22class GrContext;
Robert Phillips96601082018-05-29 16:13:26 -040023class SkImage;
Mike Reed13711eb2020-07-14 17:16:32 -040024class SkMipmap;
Robert Phillips96601082018-05-29 16:13:26 -040025class SkPicture;
Robert Phillips1a578572020-07-13 13:17:09 -040026class SkTaskGroup;
Jim Van Verth8f11e432018-10-18 14:36:59 -040027struct SkYUVAIndex;
Robert Phillips96601082018-05-29 16:13:26 -040028
Robert Phillips11c67672020-04-23 15:10:03 -040029// This class acts as a proxy for a GrBackendTexture that backs an image.
30// Whenever a promise image is created for the image, the promise image receives a ref to
31// potentially several of these objects. Once all the promise images receive their done
32// callbacks this object is deleted - removing the GrBackendTexture from VRAM.
33// Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
34// a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
35// it drops all of its refs (via "reset").
36class PromiseImageCallbackContext : public SkRefCnt {
37public:
Robert Phillipsd5f3c982020-07-07 13:18:47 -040038 PromiseImageCallbackContext(GrDirectContext* direct, GrBackendFormat backendFormat)
39 : fContext(direct)
Robert Phillips11c67672020-04-23 15:10:03 -040040 , fBackendFormat(backendFormat) {}
41
Brian Salomond0072812020-07-21 17:03:56 -040042 ~PromiseImageCallbackContext() override;
Robert Phillips11c67672020-04-23 15:10:03 -040043
44 const GrBackendFormat& backendFormat() const { return fBackendFormat; }
45
46 void setBackendTexture(const GrBackendTexture& backendTexture);
47
Robert Phillipsd5f3c982020-07-07 13:18:47 -040048 void destroyBackendTexture();
Robert Phillips11c67672020-04-23 15:10:03 -040049
50 sk_sp<SkPromiseImageTexture> fulfill() {
51 SkASSERT(fUnreleasedFulfills >= 0);
52 ++fUnreleasedFulfills;
53 ++fTotalFulfills;
54 return fPromiseImageTexture;
55 }
56
57 void release() {
58 SkASSERT(fUnreleasedFulfills > 0);
59 --fUnreleasedFulfills;
60 ++fTotalReleases;
61 }
62
63 void done() {
64 ++fDoneCnt;
65 SkASSERT(fDoneCnt <= fNumImages);
66 }
67
68 void wasAddedToImage() { fNumImages++; }
69
70 const SkPromiseImageTexture* promiseImageTexture() const {
71 return fPromiseImageTexture.get();
72 }
73
74 static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
75 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
76 return callbackContext->fulfill();
77 }
78
79 static void PromiseImageReleaseProc(void* textureContext) {
80 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
81 callbackContext->release();
82 }
83
84 static void PromiseImageDoneProc(void* textureContext) {
85 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
86 callbackContext->done();
87 callbackContext->unref();
88 }
89
90private:
Robert Phillipsd5f3c982020-07-07 13:18:47 -040091 GrDirectContext* fContext;
Robert Phillips11c67672020-04-23 15:10:03 -040092 GrBackendFormat fBackendFormat;
93 sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
94 int fNumImages = 0;
95 int fTotalFulfills = 0;
96 int fTotalReleases = 0;
97 int fUnreleasedFulfills = 0;
98 int fDoneCnt = 0;
99
John Stiles7571f9e2020-09-02 22:42:33 -0400100 using INHERITED = SkRefCnt;
Robert Phillips11c67672020-04-23 15:10:03 -0400101};
102
Robert Phillips96601082018-05-29 16:13:26 -0400103// This class consolidates tracking & extraction of the original image data from an skp,
104// the upload of said data to the GPU and the fulfillment of promise images.
105//
106// The way this works is:
107// the original skp is converted to SkData and all its image info is extracted into this
108// class and only indices into this class are left in the SkData (via deflateSKP)
109//
110// Prior to replaying in threads, all the images stored in this class are uploaded to the
111// gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
112//
113// Each thread reinflates the SkData into an SkPicture replacing all the indices w/
114// promise images (all using the same GrBackendTexture and getting a ref to the
115// appropriate PromiseImageCallbackContext) (via reinflateSKP).
116//
117// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
118//
119// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400120// are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
Robert Phillips96601082018-05-29 16:13:26 -0400121// from VRAM
122//
123// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
124// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
125class DDLPromiseImageHelper {
126public:
Brian Salomon59c60b02020-09-01 15:01:15 -0400127 DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes& supportedYUVADataTypes)
128 : fSupportedYUVADataTypes(supportedYUVADataTypes) {}
Brian Salomon7d88f312019-02-28 10:03:03 -0500129 ~DDLPromiseImageHelper() = default;
Robert Phillips96601082018-05-29 16:13:26 -0400130
131 // Convert the SkPicture into SkData replacing all the SkImages with an index.
132 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
133
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400134 void createCallbackContexts(GrDirectContext*);
Robert Phillips923181b2020-02-14 12:36:37 -0500135
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400136 void uploadAllToGPU(SkTaskGroup*, GrDirectContext*);
137 void deleteAllFromGPU(SkTaskGroup*, GrDirectContext*);
Robert Phillips96601082018-05-29 16:13:26 -0400138
139 // reinflate a deflated SKP, replacing all the indices with promise images.
140 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
141 SkData* compressedPicture,
142 SkTArray<sk_sp<SkImage>>* promiseImages) const;
143
144 // Remove this class' refs on the PromiseImageCallbackContexts
145 void reset() { fImageInfo.reset(); }
146
147private:
Robert Phillips96601082018-05-29 16:13:26 -0400148 // This is the information extracted into this class from the parsing of the skp file.
149 // Once it has all been uploaded to the GPU and distributed to the promise images, it
150 // is all dropped via "reset".
151 class PromiseImageInfo {
152 public:
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400153 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii);
154 PromiseImageInfo(PromiseImageInfo&& other);
155 ~PromiseImageInfo();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400156
157 int index() const { return fIndex; }
158 uint32_t originalUniqueID() const { return fOriginalUniqueID; }
Brian Salomon5660e8b2020-08-25 12:40:32 -0400159 bool isYUV() const { return fYUVAPixmaps.isValid(); }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400160
161 int overallWidth() const { return fImageInfo.width(); }
162 int overallHeight() const { return fImageInfo.height(); }
163 SkColorType overallColorType() const { return fImageInfo.colorType(); }
164 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
165 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
166
Brian Salomon5660e8b2020-08-25 12:40:32 -0400167 int numYUVAPlanes() const {
168 SkASSERT(this->isYUV());
169 return fYUVAPixmaps.yuvaInfo().numPlanes();
170 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400171 SkYUVColorSpace yuvColorSpace() const {
172 SkASSERT(this->isYUV());
Brian Salomon5660e8b2020-08-25 12:40:32 -0400173 return fYUVAPixmaps.yuvaInfo().yuvColorSpace();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400174 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400175 const SkYUVAIndex* yuvaIndices() const {
176 SkASSERT(this->isYUV());
Brian Salomon5660e8b2020-08-25 12:40:32 -0400177 SkASSERT(fYUVAIndices[SkYUVAIndex::kY_Index].fIndex >= 0);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400178 return fYUVAIndices;
179 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400180 const SkPixmap& yuvPixmap(int index) const {
181 SkASSERT(this->isYUV());
Brian Salomon5660e8b2020-08-25 12:40:32 -0400182 return fYUVAPixmaps.planes()[index];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400183 }
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.
John Stilesec9b4aa2020-08-07 13:05:14 -0400191 std::unique_ptr<SkPixmap[]> normalMipLevels() const;
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400192 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
Brian Salomon7e67dca2020-07-21 09:27:25 -0400207 GrMipmapped mipMapped(int index) const {
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400208 if (this->isYUV()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400209 return GrMipmapped::kNo;
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400210 }
Brian Salomon7e67dca2020-07-21 09:27:25 -0400211 return fMipLevels ? GrMipmapped::kYes : GrMipmapped::kNo;
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400212 }
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
Mike Reed13711eb2020-07-14 17:16:32 -0400222 void setMipLevels(const SkBitmap& baseLevel, std::unique_ptr<SkMipmap> mipLevels);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400223
Brian Salomonefb5f072020-07-28 21:06:43 -0400224 /** Takes ownership of the plane data. */
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400225 void setYUVPlanes(SkYUVAPixmaps yuvaPixmaps) { fYUVAPixmaps = std::move(yuvaPixmaps); }
Brian Salomon5660e8b2020-08-25 12:40:32 -0400226
227 /** Call after setYUVPlanes() and callback contexts have been installed. */
228 void initYUVAIndices();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400229
230 private:
231 const int fIndex; // index in the 'fImageInfo' array
232 const uint32_t fOriginalUniqueID; // original ID for deduping
233
234 const SkImageInfo fImageInfo; // info for the overarching image
235
Robert Phillipsf95e2f42020-04-17 16:20:55 -0400236 // CPU-side cache of a normal SkImage's mipmap levels
237 SkBitmap fBaseLevel;
Mike Reed13711eb2020-07-14 17:16:32 -0400238 std::unique_ptr<SkMipmap> fMipLevels;
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400239
240 // CPU-side cache of a YUV SkImage's contents
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400241 SkYUVAPixmaps fYUVAPixmaps;
Brian Salomon5660e8b2020-08-25 12:40:32 -0400242 SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount] = {};
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400243
Jim Van Verthe24b5872018-10-29 16:26:02 -0400244 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
245 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
Robert Phillips96601082018-05-29 16:13:26 -0400246 };
247
248 // This stack-based context allows each thread to re-inflate the image indices into
249 // promise images while still using the same GrBackendTexture.
250 struct PerRecorderContext {
251 SkDeferredDisplayListRecorder* fRecorder;
252 const DDLPromiseImageHelper* fHelper;
253 SkTArray<sk_sp<SkImage>>* fPromiseImages;
254 };
255
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400256 static void CreateBETexturesForPromiseImage(GrDirectContext*, PromiseImageInfo*);
257 static void DeleteBETexturesForPromiseImage(GrDirectContext*, PromiseImageInfo*);
Robert Phillips923181b2020-02-14 12:36:37 -0500258
Robert Phillips923181b2020-02-14 12:36:37 -0500259 static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn);
Robert Phillips96601082018-05-29 16:13:26 -0400260
261 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
262 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
Robert Phillipsd5f3c982020-07-07 13:18:47 -0400263 void uploadImage(GrDirectContext*, PromiseImageInfo*);
Robert Phillips96601082018-05-29 16:13:26 -0400264
265 // returns -1 if not found
266 int findImage(SkImage* image) const;
267
268 // returns -1 on failure
269 int addImage(SkImage* image);
270
271 // returns -1 on failure
272 int findOrDefineImage(SkImage* image);
273
Brian Salomon59c60b02020-09-01 15:01:15 -0400274 SkYUVAPixmapInfo::SupportedDataTypes fSupportedYUVADataTypes;
Robert Phillips96601082018-05-29 16:13:26 -0400275 SkTArray<PromiseImageInfo> fImageInfo;
276};
277
278#endif