blob: e9520b2d4886b79be91394827e49b3f3c18dc9e6 [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"
15
16class GrContext;
17class SkDeferredDisplayListRecorder;
18class SkImage;
19class SkPicture;
20
21// This class consolidates tracking & extraction of the original image data from an skp,
22// the upload of said data to the GPU and the fulfillment of promise images.
23//
24// The way this works is:
25// the original skp is converted to SkData and all its image info is extracted into this
26// class and only indices into this class are left in the SkData (via deflateSKP)
27//
28// Prior to replaying in threads, all the images stored in this class are uploaded to the
29// gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
30//
31// Each thread reinflates the SkData into an SkPicture replacing all the indices w/
32// promise images (all using the same GrBackendTexture and getting a ref to the
33// appropriate PromiseImageCallbackContext) (via reinflateSKP).
34//
35// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
36//
37// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
38// are done the PromiseImageCallbackContext is freed and its GrBackendTexture removed
39// from VRAM
40//
41// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
42// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
43class DDLPromiseImageHelper {
44public:
45 DDLPromiseImageHelper() { }
46
47 // Convert the SkPicture into SkData replacing all the SkImages with an index.
48 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
49
50 void uploadAllToGPU(GrContext* context);
51
52 // reinflate a deflated SKP, replacing all the indices with promise images.
53 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
54 SkData* compressedPicture,
55 SkTArray<sk_sp<SkImage>>* promiseImages) const;
56
57 // Remove this class' refs on the PromiseImageCallbackContexts
58 void reset() { fImageInfo.reset(); }
59
60private:
61 // This class acts as a proxy for the single GrBackendTexture representing an image.
62 // Whenever a promise image is created for the image, the promise image receives a ref to
63 // this object. Once all the promise images receive their done callbacks this object
64 // is deleted - removing the GrBackendTexture from VRAM.
65 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
66 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
67 // it drops all of its refs (via "reset").
68 class PromiseImageCallbackContext : public SkRefCnt {
69 public:
70 PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
71
72 ~PromiseImageCallbackContext();
73
74 void setBackendTexture(const GrBackendTexture& backendTexture) {
75 fBackendTexture = backendTexture;
76 }
77
78 const GrBackendTexture& backendTexture() const { return fBackendTexture; }
79
Timothy Liang036fdfe2018-06-28 15:50:36 -040080 const GrCaps* caps() const;
81
Robert Phillips96601082018-05-29 16:13:26 -040082 private:
83 GrContext* fContext;
84 GrBackendTexture fBackendTexture;
85
86 typedef SkRefCnt INHERITED;
87 };
88
89 // This is the information extracted into this class from the parsing of the skp file.
90 // Once it has all been uploaded to the GPU and distributed to the promise images, it
91 // is all dropped via "reset".
92 class PromiseImageInfo {
93 public:
94 int fIndex; // index in the 'fImageInfo' array
95 uint32_t fOriginalUniqueID; // original ID for deduping
96 SkBitmap fBitmap; // CPU-side cache of the contents
97 sk_sp<PromiseImageCallbackContext> fCallbackContext;
98 };
99
100 // This stack-based context allows each thread to re-inflate the image indices into
101 // promise images while still using the same GrBackendTexture.
102 struct PerRecorderContext {
103 SkDeferredDisplayListRecorder* fRecorder;
104 const DDLPromiseImageHelper* fHelper;
105 SkTArray<sk_sp<SkImage>>* fPromiseImages;
106 };
107
108 static void PromiseImageFulfillProc(void* textureContext, GrBackendTexture* outTexture) {
109 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
110 SkASSERT(callbackContext->backendTexture().isValid());
111 *outTexture = callbackContext->backendTexture();
112 }
113
114 static void PromiseImageReleaseProc(void* textureContext) {
115#ifdef SK_DEBUG
116 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
117 SkASSERT(callbackContext->backendTexture().isValid());
118#endif
119 }
120
121 static void PromiseImageDoneProc(void* textureContext) {
122 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
123 callbackContext->unref();
124 }
125
126 static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
127
128 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
129 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
130
131 // returns -1 if not found
132 int findImage(SkImage* image) const;
133
134 // returns -1 on failure
135 int addImage(SkImage* image);
136
137 // returns -1 on failure
138 int findOrDefineImage(SkImage* image);
139
140 SkTArray<PromiseImageInfo> fImageInfo;
141};
142
143#endif