Coverage Report

Created: 2024-09-14 07:19

/src/skia/include/gpu/graphite/Context.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2021 Google LLC
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 skgpu_graphite_Context_DEFINED
9
#define skgpu_graphite_Context_DEFINED
10
11
#include "include/core/SkImage.h"
12
#include "include/core/SkRefCnt.h"
13
#include "include/core/SkShader.h"
14
#include "include/gpu/graphite/ContextOptions.h"
15
#include "include/gpu/graphite/GraphiteTypes.h"
16
#include "include/gpu/graphite/Recorder.h"
17
#include "include/private/base/SingleOwner.h"
18
19
#include <chrono>
20
#include <functional>
21
#include <memory>
22
23
class SkColorSpace;
24
class SkRuntimeEffect;
25
class SkTraceMemoryDump;
26
27
namespace skgpu::graphite {
28
29
class BackendTexture;
30
class Buffer;
31
class ClientMappedBufferManager;
32
class Context;
33
class ContextPriv;
34
class GlobalCache;
35
class PaintOptions;
36
class PlotUploadTracker;
37
class QueueManager;
38
class Recording;
39
class ResourceProvider;
40
class SharedContext;
41
class TextureProxy;
42
43
class SK_API Context final {
44
public:
45
    Context(const Context&) = delete;
46
    Context(Context&&) = delete;
47
    Context& operator=(const Context&) = delete;
48
    Context& operator=(Context&&) = delete;
49
50
    ~Context();
51
52
    BackendApi backend() const;
53
54
    std::unique_ptr<Recorder> makeRecorder(const RecorderOptions& = {});
55
56
    bool insertRecording(const InsertRecordingInfo&);
57
    bool submit(SyncToCpu = SyncToCpu::kNo);
58
59
    /** Returns true if there is work that was submitted to the GPU that has not finished. */
60
    bool hasUnfinishedGpuWork() const;
61
62
    /** Makes image pixel data available to caller, possibly asynchronously. It can also rescale
63
        the image pixels.
64
65
        Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is
66
        rescaled to the size indicated by 'dstImageInfo', is then converted to the color space,
67
        color type, and alpha type of 'dstImageInfo'. A 'srcRect' that is not contained by the
68
        bounds of the image causes failure.
69
70
        When the pixel data is ready the caller's ReadPixelsCallback is called with a
71
        AsyncReadResult containing pixel data in the requested color type, alpha type, and color
72
        space. The AsyncReadResult will have count() == 1. Upon failure the callback is called with
73
        nullptr for AsyncReadResult. The callback can be triggered, for example, with a call to
74
        Context::submit(SyncToCpu::kYes).
75
76
        The data is valid for the lifetime of AsyncReadResult with the exception that the data is
77
        immediately invalidated if the Graphite context is abandoned or destroyed.
78
79
        @param src             Graphite-backed image or surface to read the data from.
80
        @param dstImageInfo    info of the requested pixels
81
        @param srcRect         subrectangle of image to read
82
        @param rescaleGamma    controls whether rescaling is done in the image's gamma or whether
83
                               the source data is transformed to a linear gamma before rescaling.
84
        @param rescaleMode     controls the technique (and cost) of the rescaling
85
        @param callback        function to call with result of the read
86
        @param context         passed to callback
87
    */
88
    void asyncRescaleAndReadPixels(const SkImage* src,
89
                                   const SkImageInfo& dstImageInfo,
90
                                   const SkIRect& srcRect,
91
                                   SkImage::RescaleGamma rescaleGamma,
92
                                   SkImage::RescaleMode rescaleMode,
93
                                   SkImage::ReadPixelsCallback callback,
94
                                   SkImage::ReadPixelsContext context);
95
    void asyncRescaleAndReadPixels(const SkSurface* src,
96
                                   const SkImageInfo& dstImageInfo,
97
                                   const SkIRect& srcRect,
98
                                   SkImage::RescaleGamma rescaleGamma,
99
                                   SkImage::RescaleMode rescaleMode,
100
                                   SkImage::ReadPixelsCallback callback,
101
                                   SkImage::ReadPixelsContext context);
102
103
    /**
104
        Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The
105
        RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three
106
        planes ordered y, u, v. The u and v planes are half the width and height of the resized
107
        rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize'
108
        width and height are not even. A 'srcRect' that is not contained by the bounds of the
109
        surface causes failure.
110
111
        When the pixel data is ready the caller's ReadPixelsCallback is called with a
112
        AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3.
113
        Upon failure the callback is called with nullptr for AsyncReadResult. The callback can
114
        be triggered, for example, with a call to Context::submit(SyncToCpu::kYes).
115
116
        The data is valid for the lifetime of AsyncReadResult with the exception that the data
117
        is immediately invalidated if the context is abandoned or destroyed.
118
119
        @param src            Graphite-backed image or surface to read the data from.
120
        @param yuvColorSpace  The transformation from RGB to YUV. Applied to the resized image
121
                              after it is converted to dstColorSpace.
122
        @param dstColorSpace  The color space to convert the resized image to, after rescaling.
123
        @param srcRect        The portion of the surface to rescale and convert to YUV planes.
124
        @param dstSize        The size to rescale srcRect to
125
        @param rescaleGamma   controls whether rescaling is done in the surface's gamma or whether
126
                              the source data is transformed to a linear gamma before rescaling.
127
        @param rescaleMode    controls the sampling technique of the rescaling
128
        @param callback       function to call with the planar read result
129
        @param context        passed to callback
130
     */
131
    void asyncRescaleAndReadPixelsYUV420(const SkImage* src,
132
                                         SkYUVColorSpace yuvColorSpace,
133
                                         sk_sp<SkColorSpace> dstColorSpace,
134
                                         const SkIRect& srcRect,
135
                                         const SkISize& dstSize,
136
                                         SkImage::RescaleGamma rescaleGamma,
137
                                         SkImage::RescaleMode rescaleMode,
138
                                         SkImage::ReadPixelsCallback callback,
139
                                         SkImage::ReadPixelsContext context);
140
    void asyncRescaleAndReadPixelsYUV420(const SkSurface* src,
141
                                         SkYUVColorSpace yuvColorSpace,
142
                                         sk_sp<SkColorSpace> dstColorSpace,
143
                                         const SkIRect& srcRect,
144
                                         const SkISize& dstSize,
145
                                         SkImage::RescaleGamma rescaleGamma,
146
                                         SkImage::RescaleMode rescaleMode,
147
                                         SkImage::ReadPixelsCallback callback,
148
                                         SkImage::ReadPixelsContext context);
149
150
    /**
151
     * Identical to asyncRescaleAndReadPixelsYUV420 but a fourth plane is returned in the
152
     * AsyncReadResult passed to 'callback'. The fourth plane contains the alpha chanel at the
153
     * same full resolution as the Y plane.
154
     */
155
    void asyncRescaleAndReadPixelsYUVA420(const SkImage* src,
156
                                          SkYUVColorSpace yuvColorSpace,
157
                                          sk_sp<SkColorSpace> dstColorSpace,
158
                                          const SkIRect& srcRect,
159
                                          const SkISize& dstSize,
160
                                          SkImage::RescaleGamma rescaleGamma,
161
                                          SkImage::RescaleMode rescaleMode,
162
                                          SkImage::ReadPixelsCallback callback,
163
                                          SkImage::ReadPixelsContext context);
164
    void asyncRescaleAndReadPixelsYUVA420(const SkSurface* src,
165
                                          SkYUVColorSpace yuvColorSpace,
166
                                          sk_sp<SkColorSpace> dstColorSpace,
167
                                          const SkIRect& srcRect,
168
                                          const SkISize& dstSize,
169
                                          SkImage::RescaleGamma rescaleGamma,
170
                                          SkImage::RescaleMode rescaleMode,
171
                                          SkImage::ReadPixelsCallback callback,
172
                                          SkImage::ReadPixelsContext context);
173
174
    /**
175
     * Checks whether any asynchronous work is complete and if so calls related callbacks.
176
     */
177
    void checkAsyncWorkCompletion();
178
179
    /**
180
     * Called to delete the passed in BackendTexture. This should only be called if the
181
     * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder created
182
     * from this Context. If the BackendTexture is not valid or does not match the BackendApi of the
183
     * Context then nothing happens.
184
     *
185
     * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture.
186
     * The BackendTexture will be reset to an invalid state and should not be used again.
187
     */
188
    void deleteBackendTexture(const BackendTexture&);
189
190
    /**
191
     * Frees GPU resources created and held by the Context. Can be called to reduce GPU memory
192
     * pressure. Any resources that are still in use (e.g. being used by work submitted to the GPU)
193
     * will not be deleted by this call. If the caller wants to make sure all resources are freed,
194
     * then they should first make sure to submit and wait on any outstanding work.
195
     */
196
    void freeGpuResources();
197
198
    /**
199
     * Purge GPU resources on the Context that haven't been used in the past 'msNotUsed'
200
     * milliseconds or are otherwise marked for deletion, regardless of whether the context is under
201
     * budget.
202
     */
203
    void performDeferredCleanup(std::chrono::milliseconds msNotUsed);
204
205
    /**
206
     * Returns the number of bytes of the Context's gpu memory cache budget that are currently in
207
     * use.
208
     */
209
    size_t currentBudgetedBytes() const;
210
211
    /**
212
     * Returns the number of bytes of the Context's resource cache that are currently purgeable.
213
     */
214
    size_t currentPurgeableBytes() const;
215
216
    /**
217
     * Returns the size of Context's gpu memory cache budget in bytes.
218
     */
219
    size_t maxBudgetedBytes() const;
220
221
    /**
222
     * Enumerates all cached GPU resources owned by the Context and dumps their memory to
223
     * traceMemoryDump.
224
     */
225
    void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
226
227
    /**
228
     * Returns true if the backend-specific context has gotten into an unrecoverarble, lost state
229
     * (e.g. if we've gotten a VK_ERROR_DEVICE_LOST in the Vulkan backend).
230
     */
231
    bool isDeviceLost() const;
232
233
    /**
234
     * Returns the maximum texture dimension supported by the underlying backend.
235
     */
236
    int maxTextureSize() const;
237
238
    /*
239
     * Does this context support protected content?
240
     */
241
    bool supportsProtectedContent() const;
242
243
    // Provides access to functions that aren't part of the public API.
244
    ContextPriv priv();
245
    const ContextPriv priv() const;  // NOLINT(readability-const-return-type)
246
247
    class ContextID {
248
    public:
249
        static Context::ContextID Next();
250
251
0
        ContextID() : fID(SK_InvalidUniqueID) {}
252
253
0
        bool operator==(const ContextID& that) const { return fID == that.fID; }
254
0
        bool operator!=(const ContextID& that) const { return !(*this == that); }
255
256
0
        void makeInvalid() { fID = SK_InvalidUniqueID; }
257
0
        bool isValid() const { return fID != SK_InvalidUniqueID; }
258
259
    private:
260
0
        constexpr ContextID(uint32_t id) : fID(id) {}
261
        uint32_t fID;
262
    };
263
264
0
    ContextID contextID() const { return fContextID; }
265
266
protected:
267
    Context(sk_sp<SharedContext>, std::unique_ptr<QueueManager>, const ContextOptions&);
268
269
private:
270
    friend class ContextPriv;
271
    friend class ContextCtorAccessor;
272
273
    struct PixelTransferResult {
274
        using ConversionFn = void(void* dst, const void* mappedBuffer);
275
        // If null then the transfer could not be performed. Otherwise this buffer will contain
276
        // the pixel data when the transfer is complete.
277
        sk_sp<Buffer> fTransferBuffer;
278
        // Size of the read.
279
        SkISize fSize;
280
        // RowBytes for transfer buffer data
281
        size_t fRowBytes;
282
        // If this is null then the transfer buffer will contain the data in the requested
283
        // color type. Otherwise, when the transfer is done this must be called to convert
284
        // from the transfer buffer's color type to the requested color type.
285
        std::function<ConversionFn> fPixelConverter;
286
    };
287
288
0
    SingleOwner* singleOwner() const { return &fSingleOwner; }
289
290
    // Must be called in Make() to handle one-time GPU setup operations that can possibly fail and
291
    // require Context::Make() to return a nullptr.
292
    bool finishInitialization();
293
294
    void checkForFinishedWork(SyncToCpu);
295
296
    std::unique_ptr<Recorder> makeInternalRecorder() const;
297
298
    template <typename SrcPixels> struct AsyncParams;
299
300
    template <typename ReadFn, typename... ExtraArgs>
301
    void asyncRescaleAndReadImpl(ReadFn Context::* asyncRead,
302
                                 SkImage::RescaleGamma rescaleGamma,
303
                                 SkImage::RescaleMode rescaleMode,
304
                                 const AsyncParams<SkImage>&,
305
                                 ExtraArgs...);
306
307
    // Recorder is optional and will be used if drawing operations are required. If no Recorder is
308
    // provided but drawing operations are needed, a new Recorder will be created automatically.
309
    void asyncReadPixels(std::unique_ptr<Recorder>, const AsyncParams<SkImage>&);
310
    void asyncReadPixelsYUV420(std::unique_ptr<Recorder>,
311
                               const AsyncParams<SkImage>&,
312
                               SkYUVColorSpace);
313
314
    // Like asyncReadPixels() except it performs no fallbacks, and requires that the texture be
315
    // readable. However, the texture does not need to be sampleable.
316
    void asyncReadTexture(std::unique_ptr<Recorder>,
317
                          const AsyncParams<TextureProxy>&,
318
                          const SkColorInfo& srcColorInfo);
319
320
    // Inserts a texture to buffer transfer task, used by asyncReadPixels methods. If the
321
    // Recorder is non-null, tasks will be added to the Recorder's list; otherwise the transfer
322
    // tasks will be added to the queue manager directly.
323
    PixelTransferResult transferPixels(Recorder*,
324
                                       const TextureProxy* srcProxy,
325
                                       const SkColorInfo& srcColorInfo,
326
                                       const SkColorInfo& dstColorInfo,
327
                                       const SkIRect& srcRect);
328
329
    // If the recorder is non-null, it will be snapped and inserted with the assumption that the
330
    // copy tasks (and possibly preparatory draw tasks) have already been added to the Recording.
331
    void finalizeAsyncReadPixels(std::unique_ptr<Recorder>,
332
                                 SkSpan<PixelTransferResult>,
333
                                 SkImage::ReadPixelsCallback callback,
334
                                 SkImage::ReadPixelsContext callbackContext);
335
336
    sk_sp<SharedContext> fSharedContext;
337
    std::unique_ptr<ResourceProvider> fResourceProvider;
338
    std::unique_ptr<QueueManager> fQueueManager;
339
    std::unique_ptr<ClientMappedBufferManager> fMappedBufferManager;
340
341
    // In debug builds we guard against improper thread handling. This guard is passed to the
342
    // ResourceCache for the Context.
343
    mutable SingleOwner fSingleOwner;
344
345
#if defined(GPU_TEST_UTILS)
346
    // In test builds a Recorder may track the Context that was used to create it.
347
    bool fStoreContextRefInRecorder = false;
348
    // If this tracking is on, to allow the client to safely delete this Context or its Recorders
349
    // in any order we must also track the Recorders created here.
350
    std::vector<Recorder*> fTrackedRecorders;
351
#endif
352
353
    // Needed for MessageBox handling
354
    const ContextID fContextID;
355
};
356
357
} // namespace skgpu::graphite
358
359
#endif // skgpu_graphite_Context_DEFINED