blob: 5bc97afc34b8f413d595d39fa8f3502da2a35b2b [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
80 private:
81 GrContext* fContext;
82 GrBackendTexture fBackendTexture;
83
84 typedef SkRefCnt INHERITED;
85 };
86
87 // This is the information extracted into this class from the parsing of the skp file.
88 // Once it has all been uploaded to the GPU and distributed to the promise images, it
89 // is all dropped via "reset".
90 class PromiseImageInfo {
91 public:
92 int fIndex; // index in the 'fImageInfo' array
93 uint32_t fOriginalUniqueID; // original ID for deduping
94 SkBitmap fBitmap; // CPU-side cache of the contents
95 sk_sp<PromiseImageCallbackContext> fCallbackContext;
96 };
97
98 // This stack-based context allows each thread to re-inflate the image indices into
99 // promise images while still using the same GrBackendTexture.
100 struct PerRecorderContext {
101 SkDeferredDisplayListRecorder* fRecorder;
102 const DDLPromiseImageHelper* fHelper;
103 SkTArray<sk_sp<SkImage>>* fPromiseImages;
104 };
105
106 static void PromiseImageFulfillProc(void* textureContext, GrBackendTexture* outTexture) {
107 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
108 SkASSERT(callbackContext->backendTexture().isValid());
109 *outTexture = callbackContext->backendTexture();
110 }
111
112 static void PromiseImageReleaseProc(void* textureContext) {
113#ifdef SK_DEBUG
114 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
115 SkASSERT(callbackContext->backendTexture().isValid());
116#endif
117 }
118
119 static void PromiseImageDoneProc(void* textureContext) {
120 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
121 callbackContext->unref();
122 }
123
124 static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
125
126 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
127 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
128
129 // returns -1 if not found
130 int findImage(SkImage* image) const;
131
132 // returns -1 on failure
133 int addImage(SkImage* image);
134
135 // returns -1 on failure
136 int findOrDefineImage(SkImage* image);
137
138 SkTArray<PromiseImageInfo> fImageInfo;
139};
140
141#endif