Coverage Report

Created: 2024-05-20 07:14

/src/skia/tools/DDLPromiseImageHelper.h
Line
Count
Source (jump to first uncovered line)
1
/*
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 "include/core/SkBitmap.h"
12
#include "include/core/SkRefCnt.h"
13
#include "include/core/SkYUVAPixmaps.h"
14
#include "include/gpu/GrBackendSurface.h"
15
#include "include/private/base/SkTArray.h"
16
#include "include/private/chromium/GrPromiseImageTexture.h"
17
#include "src/base/SkTLazy.h"
18
#include "src/core/SkCachedData.h"
19
20
class GrContextThreadSafeProxy;
21
class GrDirectContext;
22
class SkImage;
23
class SkMipmap;
24
class SkPicture;
25
class SkTaskGroup;
26
27
// This class acts as a proxy for a GrBackendTexture that backs an image.
28
// Whenever a promise image is created for the image, the promise image receives a ref to
29
// potentially several of these objects. Once all the promise images receive their done
30
// callbacks this object is deleted - removing the GrBackendTexture from VRAM.
31
// Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
32
// a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
33
// it drops all of its refs (via "reset").
34
class PromiseImageCallbackContext : public SkRefCnt {
35
public:
36
    PromiseImageCallbackContext(GrDirectContext* direct, GrBackendFormat backendFormat)
37
            : fContext(direct)
38
0
            , fBackendFormat(backendFormat) {}
39
40
    ~PromiseImageCallbackContext() override;
41
42
0
    const GrBackendFormat& backendFormat() const { return fBackendFormat; }
43
44
    void setBackendTexture(const GrBackendTexture& backendTexture);
45
46
    void destroyBackendTexture();
47
48
0
    sk_sp<GrPromiseImageTexture> fulfill() {
49
0
        ++fTotalFulfills;
50
0
        return fPromiseImageTexture;
51
0
    }
52
53
0
    void release() {
54
0
        ++fDoneCnt;
55
0
        SkASSERT(fDoneCnt <= fNumImages);
56
0
    }
Unexecuted instantiation: PromiseImageCallbackContext::release()
Unexecuted instantiation: PromiseImageCallbackContext::release()
57
58
0
    void wasAddedToImage() { fNumImages++; }
59
60
0
    const GrPromiseImageTexture* promiseImageTexture() const {
61
0
        return fPromiseImageTexture.get();
62
0
    }
63
64
0
    static sk_sp<GrPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
65
0
        auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
66
0
        return callbackContext->fulfill();
67
0
    }
68
69
0
    static void PromiseImageReleaseProc(void* textureContext) {
70
0
        auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
71
0
        callbackContext->release();
72
0
        callbackContext->unref();
73
0
    }
74
75
private:
76
    GrDirectContext*             fContext;
77
    GrBackendFormat              fBackendFormat;
78
    sk_sp<GrPromiseImageTexture> fPromiseImageTexture;
79
    int                          fNumImages = 0;
80
    int                          fTotalFulfills = 0;
81
    int                          fDoneCnt = 0;
82
83
    using INHERITED = SkRefCnt;
84
};
85
86
// This class consolidates tracking & extraction of the original image data from an skp,
87
// the upload of said data to the GPU and the fulfillment of promise images.
88
//
89
// The way this works is:
90
//    the original skp is converted to SkData and all its image info is extracted into this
91
//       class and only indices into this class are left in the SkData
92
//    the PromiseImageCallbackContexts are created for each image
93
//    the SkData is then reinflated into an SkPicture with promise images replacing all the indices
94
//       (all in recreateSKP)
95
//
96
//    Prior to replaying in threads, all the images are uploaded to the gpu
97
//       (in uploadAllToGPU)
98
//
99
//    This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
100
//
101
//    Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
102
//       are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
103
//       from VRAM
104
//
105
// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
106
// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
107
class DDLPromiseImageHelper {
108
public:
109
    DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes& supportedYUVADataTypes)
110
0
            : fSupportedYUVADataTypes(supportedYUVADataTypes) {}
111
    ~DDLPromiseImageHelper() = default;
112
113
    // Convert the input SkPicture into a new one which has promise images rather than live
114
    // images.
115
    sk_sp<SkPicture> recreateSKP(GrDirectContext*, SkPicture*);
116
117
    void uploadAllToGPU(SkTaskGroup*, GrDirectContext*);
118
    void deleteAllFromGPU(SkTaskGroup*, GrDirectContext*);
119
120
    // Remove this class' refs on the promise images and the PromiseImageCallbackContexts
121
0
    void reset() {
122
0
        fImageInfo.clear();
123
0
        fPromiseImages.clear();
124
0
    }
125
126
private:
127
    void createCallbackContexts(GrDirectContext*);
128
    // reinflate a deflated SKP, replacing all the indices with promise images.
129
    sk_sp<SkPicture> reinflateSKP(sk_sp<GrContextThreadSafeProxy>, SkData* deflatedSKP);
130
131
    // This is the information extracted into this class from the parsing of the skp file.
132
    // Once it has all been uploaded to the GPU and distributed to the promise images, it
133
    // is all dropped via "reset".
134
    class PromiseImageInfo {
135
    public:
136
        PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii);
137
        PromiseImageInfo(PromiseImageInfo&& other);
138
        ~PromiseImageInfo();
139
140
0
        int index() const { return fIndex; }
141
0
        uint32_t originalUniqueID() const { return fOriginalUniqueID; }
142
0
        bool isYUV() const { return fYUVAPixmaps.isValid(); }
143
144
0
        SkISize overallDimensions() const { return fImageInfo.dimensions(); }
145
0
        SkColorType overallColorType() const { return fImageInfo.colorType(); }
146
0
        SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
147
0
        sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
148
149
0
        const SkYUVAInfo& yuvaInfo() const { return fYUVAPixmaps.yuvaInfo(); }
150
151
0
        const SkPixmap& yuvPixmap(int index) const {
152
0
            SkASSERT(this->isYUV());
153
0
            return fYUVAPixmaps.planes()[index];
154
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::yuvPixmap(int) const
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::yuvPixmap(int) const
155
156
0
        const SkBitmap& baseLevel() const {
157
0
            SkASSERT(!this->isYUV());
158
0
            return fBaseLevel;
159
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::baseLevel() const
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::baseLevel() const
160
        // This returns an array of all the available mipLevels - suitable for passing into
161
        // createBackendTexture.
162
        std::unique_ptr<SkPixmap[]> normalMipLevels() const;
163
        int numMipLevels() const;
164
165
0
        void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
166
0
            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1));
167
0
            fCallbackContexts[index] = callbackContext;
168
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::setCallbackContext(int, sk_sp<PromiseImageCallbackContext>)
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::setCallbackContext(int, sk_sp<PromiseImageCallbackContext>)
169
0
        PromiseImageCallbackContext* callbackContext(int index) const {
170
0
            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1));
171
0
            return fCallbackContexts[index].get();
172
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::callbackContext(int) const
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::callbackContext(int) const
173
0
        sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
174
0
            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1));
175
0
            return fCallbackContexts[index];
176
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::refCallbackContext(int) const
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::refCallbackContext(int) const
177
178
0
        skgpu::Mipmapped mipmapped(int index) const {
179
0
            if (this->isYUV()) {
180
0
                return skgpu::Mipmapped::kNo;
181
0
            }
182
0
            return fMipLevels ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
183
0
        }
184
0
        const GrBackendFormat& backendFormat(int index) const {
185
0
            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1));
186
0
            return fCallbackContexts[index]->backendFormat();
187
0
        }
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::backendFormat(int) const
Unexecuted instantiation: DDLPromiseImageHelper::PromiseImageInfo::backendFormat(int) const
188
0
        const GrPromiseImageTexture* promiseTexture(int index) const {
189
0
            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVAInfo::kMaxPlanes : 1));
190
0
            return fCallbackContexts[index]->promiseImageTexture();
191
0
        }
192
193
        void setMipLevels(const SkBitmap& baseLevel, std::unique_ptr<SkMipmap> mipLevels);
194
195
        /** Takes ownership of the plane data. */
196
0
        void setYUVPlanes(SkYUVAPixmaps yuvaPixmaps) { fYUVAPixmaps = std::move(yuvaPixmaps); }
197
198
    private:
199
        const int                          fIndex;                // index in the 'fImageInfo' array
200
        const uint32_t                     fOriginalUniqueID;     // original ID for deduping
201
202
        const SkImageInfo                  fImageInfo;            // info for the overarching image
203
204
        // CPU-side cache of a normal SkImage's mipmap levels
205
        SkBitmap                           fBaseLevel;
206
        std::unique_ptr<SkMipmap>          fMipLevels;
207
208
        // CPU-side cache of a YUV SkImage's contents
209
        SkYUVAPixmaps                      fYUVAPixmaps;
210
211
        // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
212
        sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVAInfo::kMaxPlanes];
213
    };
214
215
    struct DeserialImageProcContext {
216
        sk_sp<GrContextThreadSafeProxy> fThreadSafeProxy;
217
        DDLPromiseImageHelper*          fHelper;
218
    };
219
220
    static void CreateBETexturesForPromiseImage(GrDirectContext*, PromiseImageInfo*);
221
    static void DeleteBETexturesForPromiseImage(PromiseImageInfo*);
222
223
    static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn);
224
225
0
    bool isValidID(int id) const { return id >= 0 && id < fImageInfo.size(); }
226
0
    const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
227
    void uploadImage(GrDirectContext*, PromiseImageInfo*);
228
229
    // returns -1 if not found
230
    int findImage(SkImage* image) const;
231
232
    // returns -1 on failure
233
    int addImage(SkImage* image);
234
235
    // returns -1 on failure
236
    int findOrDefineImage(SkImage* image);
237
238
    SkYUVAPixmapInfo::SupportedDataTypes   fSupportedYUVADataTypes;
239
    skia_private::TArray<PromiseImageInfo> fImageInfo;
240
241
    // TODO: review the use of 'fPromiseImages' - it doesn't seem useful/necessary
242
    skia_private::TArray<sk_sp<SkImage>>   fPromiseImages;    // All the promise images in the
243
                                                            // reconstituted picture
244
};
245
246
#endif