xref: /aosp_15_r20/external/skia/include/gpu/graphite/Recorder.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_Recorder_DEFINED
9 #define skgpu_graphite_Recorder_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "include/core/SkSize.h"
13 #include "include/gpu/graphite/GraphiteTypes.h"
14 #include "include/gpu/graphite/Recording.h"
15 #include "include/private/base/SingleOwner.h"
16 #include "include/private/base/SkTArray.h"
17 
18 #include <chrono>
19 
20 struct AHardwareBuffer;
21 class SkCanvas;
22 struct SkImageInfo;
23 class SkPixmap;
24 class SkTraceMemoryDump;
25 
26 namespace skgpu {
27 class RefCntedCallback;
28 class TokenTracker;
29 }
30 
31 namespace sktext::gpu {
32 class StrikeCache;
33 class TextBlobRedrawCoordinator;
34 }
35 
36 namespace skgpu::graphite {
37 
38 class AtlasProvider;
39 class BackendTexture;
40 class Caps;
41 class Context;
42 class Device;
43 class DrawBufferManager;
44 class GlobalCache;
45 class ImageProvider;
46 class ProxyCache;
47 class ProxyReadCountMap;
48 class RecorderPriv;
49 class ResourceProvider;
50 class RuntimeEffectDictionary;
51 class SharedContext;
52 class Task;
53 class TaskList;
54 class TextureDataBlock;
55 class TextureInfo;
56 class UniformDataBlock;
57 class UploadBufferManager;
58 class UploadList;
59 
60 template<typename T> class PipelineDataCache;
61 using TextureDataCache = PipelineDataCache<TextureDataBlock>;
62 
63 struct SK_API RecorderOptions final {
64     RecorderOptions();
65     RecorderOptions(const RecorderOptions&);
66     ~RecorderOptions();
67 
68     sk_sp<ImageProvider> fImageProvider;
69 
70     static constexpr size_t kDefaultRecorderBudget = 256 * (1 << 20);
71     // What is the budget for GPU resources allocated and held by this Recorder.
72     size_t fGpuBudgetInBytes = kDefaultRecorderBudget;
73 };
74 
75 class SK_API Recorder final {
76 public:
77     Recorder(const Recorder&) = delete;
78     Recorder(Recorder&&) = delete;
79     Recorder& operator=(const Recorder&) = delete;
80     Recorder& operator=(Recorder&&) = delete;
81 
82     ~Recorder();
83 
84     BackendApi backend() const;
85 
86     std::unique_ptr<Recording> snap();
87 
clientImageProvider()88     ImageProvider* clientImageProvider() { return fClientImageProvider.get(); }
clientImageProvider()89     const ImageProvider* clientImageProvider() const { return fClientImageProvider.get(); }
90 
91     /**
92      * Gets the maximum supported texture size.
93      */
94     int maxTextureSize() const;
95 
96     /**
97      * Creates a new backend gpu texture matching the dimensions and TextureInfo. If an invalid
98      * TextureInfo or a TextureInfo Skia can't support is passed in, this will return an invalid
99      * BackendTexture. Thus the client should check isValid on the returned BackendTexture to know
100      * if it succeeded or not.
101      *
102      * If this does return a valid BackendTexture, the caller is required to use
103      * Recorder::deleteBackendTexture or Context::deleteBackendTexture to delete the texture. It is
104      * safe to use the Context that created this Recorder or any other Recorder created from the
105      * same Context to call deleteBackendTexture.
106      */
107     BackendTexture createBackendTexture(SkISize dimensions, const TextureInfo&);
108 
109 #ifdef SK_BUILD_FOR_ANDROID
110     BackendTexture createBackendTexture(AHardwareBuffer*,
111                                         bool isRenderable,
112                                         bool isProtectedContent,
113                                         SkISize dimensions,
114                                         bool fromAndroidWindow = false) const;
115 #endif
116 
117     /**
118      * If possible, updates a backend texture with the provided pixmap data. The client
119      * should check the return value to see if the update was successful. The client is required
120      * to insert a Recording into the Context and call `submit` to send the upload work to the gpu.
121      * The backend texture must be compatible with the provided pixmap(s). Compatible, in this case,
122      * means that the backend format is compatible with the base pixmap's colortype. The src data
123      * can be deleted when this call returns. When the BackendTexture is safe to be destroyed by the
124      * client, Skia will call the passed in GpuFinishedProc. The BackendTexture should not be
125      * destroyed before that.
126      * If the backend texture is mip mapped, the data for all the mipmap levels must be provided.
127      * In the mipmapped case all the colortypes of the provided pixmaps must be the same.
128      * Additionally, all the miplevels must be sized correctly (please see
129      * SkMipmap::ComputeLevelSize and ComputeLevelCount).
130      * Note: the pixmap's alphatypes and colorspaces are ignored.
131      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
132      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
133      */
134     bool updateBackendTexture(const BackendTexture&,
135                               const SkPixmap srcData[],
136                               int numLevels,
137                               GpuFinishedProc = nullptr,
138                               GpuFinishedContext = nullptr);
139 
140     /**
141      * If possible, updates a compressed backend texture filled with the provided raw data. The
142      * client should check the return value to see if the update was successful. The client is
143      * required to insert a Recording into the Context and call `submit` to send the upload work to
144      * the gpu. When the BackendTexture is safe to be destroyed by the client, Skia will call the
145      * passed in GpuFinishedProc. The BackendTexture should not be destroyed before that.
146      * If the backend texture is mip mapped, the data for all the mipmap levels must be provided.
147      * Additionally, all the miplevels must be sized correctly (please see
148      * SkMipMap::ComputeLevelSize and ComputeLevelCount).
149      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
150      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
151      */
152     bool updateCompressedBackendTexture(const BackendTexture&,
153                                         const void* data,
154                                         size_t dataSize,
155                                         GpuFinishedProc = nullptr,
156                                         GpuFinishedContext = nullptr);
157 
158     /**
159      * Called to delete the passed in BackendTexture. This should only be called if the
160      * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder that is
161      * associated with the same Context. If the BackendTexture is not valid or does not match the
162      * BackendApi of the Recorder then nothing happens.
163      *
164      * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture.
165      * The BackendTexture will be reset to an invalid state and should not be used again.
166      */
167     void deleteBackendTexture(const BackendTexture&);
168 
169     // Adds a proc that will be moved to the Recording upon snap, subsequently attached to the
170     // CommandBuffer when the Recording is added, and called when that CommandBuffer is submitted
171     // and finishes. If the Recorder or Recording is deleted before the proc is added to the
172     // CommandBuffer, it will be called with result Failure.
173     void addFinishInfo(const InsertFinishInfo&);
174 
175     // Returns a canvas that will record to a proxy surface, which must be instantiated on replay.
176     // This can only be called once per Recording; subsequent calls will return null until a
177     // Recording is snapped. Additionally, the returned SkCanvas is only valid until the next
178     // Recording snap, at which point it is deleted.
179     SkCanvas* makeDeferredCanvas(const SkImageInfo&, const TextureInfo&);
180 
181     /**
182      * Frees GPU resources created and held by the Recorder. Can be called to reduce GPU memory
183      * pressure. Any resources that are still in use (e.g. being used by work submitted to the GPU)
184      * will not be deleted by this call. If the caller wants to make sure all resources are freed,
185      * then they should first make sure to submit and wait on any outstanding work.
186      */
187     void freeGpuResources();
188 
189     /**
190      * Purge GPU resources on the Recorder that haven't been used in the past 'msNotUsed'
191      * milliseconds or are otherwise marked for deletion, regardless of whether the context is under
192      * budget.
193      */
194     void performDeferredCleanup(std::chrono::milliseconds msNotUsed);
195 
196     /**
197      * Returns the number of bytes of the Recorder's gpu memory cache budget that are currently in
198      * use.
199      */
200     size_t currentBudgetedBytes() const;
201 
202     /**
203      * Returns the number of bytes of the Recorder's resource cache that are currently purgeable.
204      */
205     size_t currentPurgeableBytes() const;
206 
207     /**
208      * Returns the size of Recorder's gpu memory cache budget in bytes.
209      */
210     size_t maxBudgetedBytes() const;
211 
212     /**
213      * Enumerates all cached GPU resources owned by the Recorder and dumps their memory to
214      * traceMemoryDump.
215      */
216     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
217 
218     // Provides access to functions that aren't part of the public API.
219     RecorderPriv priv();
220     const RecorderPriv priv() const;  // NOLINT(readability-const-return-type)
221 
222 private:
223     friend class Context; // For ctor
224     friend class Device; // For registering and deregistering Devices;
225     friend class RecorderPriv; // for ctor and hidden methods
226 
227     // If Context is non-null, the Recorder will use the Context's resource provider
228     // instead of creating its own.
229     Recorder(sk_sp<SharedContext>, const RecorderOptions&, const Context*);
230 
singleOwner()231     SingleOwner* singleOwner() const { return &fSingleOwner; }
232 
233     // We keep track of all Devices that are connected to a Recorder. This allows the client to
234     // safely delete an SkSurface or a Recorder in any order. If the client deletes the Recorder
235     // we need to notify all Devices that the Recorder is no longer valid. If we delete the
236     // SkSurface/Device first we will flush all the Device's into the Recorder before deregistering
237     // it from the Recorder.
238     //
239     // We take a ref on the Device so that ~Device() does not have to deregister the recorder
240     // (which can happen on any thread if the Device outlives the Surface via an Image view).
241     // Recorder::flushTrackedDevices() cleans up uniquely held and immutable Devices on the recorder
242     // thread so this extra ref is not significantly increasing the Device lifetime.
243     //
244     // Note: We could probably get by with only registering Devices directly connected to
245     // SkSurfaces. All other one off Devices will be created in a controlled scope where the
246     // Recorder should still be valid by the time they need to flush their work when the Device is
247     // deleted. We would have to make sure we safely handle cases where a client calls saveLayer
248     // then either deletes the SkSurface or Recorder before calling restore. For simplicity we just
249     // register every device for now, but if we see extra overhead in pushing back the extra
250     // pointers, we can look into only registering SkSurface Devices.
251     void registerDevice(sk_sp<Device>);
252     void deregisterDevice(const Device*);
253 
254     sk_sp<SharedContext> fSharedContext;
255     ResourceProvider* fResourceProvider; // May point to the Context's resource provider
256     std::unique_ptr<ResourceProvider> fOwnedResourceProvider; // May be null
257     std::unique_ptr<RuntimeEffectDictionary> fRuntimeEffectDict;
258 
259     // NOTE: These are stored by pointer to allow them to be forward declared.
260     std::unique_ptr<TaskList> fRootTaskList;
261     // Aggregated one-time uploads that preceed all tasks in the root task list.
262     std::unique_ptr<UploadList> fRootUploads;
263 
264     std::unique_ptr<TextureDataCache> fTextureDataCache;
265     std::unique_ptr<DrawBufferManager> fDrawBufferManager;
266     std::unique_ptr<UploadBufferManager> fUploadBufferManager;
267     std::unique_ptr<ProxyReadCountMap> fProxyReadCounts;
268 
269     // Iterating over tracked devices in flushTrackedDevices() needs to be re-entrant and support
270     // additions to fTrackedDevices if registerDevice() is triggered by a temporary device during
271     // flushing. Removals are handled by setting elements to null; final clean up is handled at the
272     // end of the initial call to flushTrackedDevices().
273     skia_private::TArray<sk_sp<Device>> fTrackedDevices;
274     int fFlushingDevicesIndex = -1;
275 
276     uint32_t fUniqueID;  // Needed for MessageBox handling for text
277     uint32_t fNextRecordingID = 1;
278     std::unique_ptr<AtlasProvider> fAtlasProvider;
279     std::unique_ptr<TokenTracker> fTokenTracker;
280     std::unique_ptr<sktext::gpu::StrikeCache> fStrikeCache;
281     std::unique_ptr<sktext::gpu::TextBlobRedrawCoordinator> fTextBlobCache;
282     sk_sp<ImageProvider> fClientImageProvider;
283 
284     // In debug builds we guard against improper thread handling
285     // This guard is passed to the ResourceCache.
286     // TODO: Should we also pass this to Device, DrawContext, and similar classes?
287     mutable SingleOwner fSingleOwner;
288 
289     sk_sp<Device> fTargetProxyDevice;
290     std::unique_ptr<SkCanvas> fTargetProxyCanvas;
291     std::unique_ptr<Recording::LazyProxyData> fTargetProxyData;
292 
293     skia_private::TArray<sk_sp<RefCntedCallback>> fFinishedProcs;
294 
295 #if defined(GPU_TEST_UTILS)
296     // For testing use only -- the Context used to create this Recorder
297     Context* fContext = nullptr;
298 #endif
299 };
300 
301 } // namespace skgpu::graphite
302 
303 #endif // skgpu_graphite_Recorder_DEFINED
304