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