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