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 * Sets the size of Context's gpu memory cache budget in bytes. If the new budget is lower than 232 * the current budget, the cache will try to free resources to get under the new budget. 233 */ 234 void setMaxBudgetedBytes(size_t bytes); 235 236 /** 237 * Enumerates all cached GPU resources owned by the Context and dumps their memory to 238 * traceMemoryDump. 239 */ 240 void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 241 242 /** 243 * Returns true if the backend-specific context has gotten into an unrecoverarble, lost state 244 * (e.g. if we've gotten a VK_ERROR_DEVICE_LOST in the Vulkan backend). 245 */ 246 bool isDeviceLost() const; 247 248 /** 249 * Returns the maximum texture dimension supported by the underlying backend. 250 */ 251 int maxTextureSize() const; 252 253 /* 254 * Does this context support protected content? 255 */ 256 bool supportsProtectedContent() const; 257 258 /* 259 * Gets the types of GPU stats supported by this Context. 260 */ 261 GpuStatsFlags supportedGpuStats() const; 262 263 // Provides access to functions that aren't part of the public API. 264 ContextPriv priv(); 265 const ContextPriv priv() const; // NOLINT(readability-const-return-type) 266 267 class ContextID { 268 public: 269 static Context::ContextID Next(); 270 ContextID()271 ContextID() : fID(SK_InvalidUniqueID) {} 272 273 bool operator==(const ContextID& that) const { return fID == that.fID; } 274 bool operator!=(const ContextID& that) const { return !(*this == that); } 275 makeInvalid()276 void makeInvalid() { fID = SK_InvalidUniqueID; } isValid()277 bool isValid() const { return fID != SK_InvalidUniqueID; } 278 279 private: ContextID(uint32_t id)280 constexpr ContextID(uint32_t id) : fID(id) {} 281 uint32_t fID; 282 }; 283 contextID()284 ContextID contextID() const { return fContextID; } 285 286 protected: 287 Context(sk_sp<SharedContext>, std::unique_ptr<QueueManager>, const ContextOptions&); 288 289 private: 290 friend class ContextPriv; 291 friend class ContextCtorAccessor; 292 293 struct PixelTransferResult { 294 using ConversionFn = void(void* dst, const void* mappedBuffer); 295 // If null then the transfer could not be performed. Otherwise this buffer will contain 296 // the pixel data when the transfer is complete. 297 sk_sp<Buffer> fTransferBuffer; 298 // Size of the read. 299 SkISize fSize; 300 // RowBytes for transfer buffer data 301 size_t fRowBytes; 302 // If this is null then the transfer buffer will contain the data in the requested 303 // color type. Otherwise, when the transfer is done this must be called to convert 304 // from the transfer buffer's color type to the requested color type. 305 std::function<ConversionFn> fPixelConverter; 306 }; 307 singleOwner()308 SingleOwner* singleOwner() const { return &fSingleOwner; } 309 310 // Must be called in Make() to handle one-time GPU setup operations that can possibly fail and 311 // require Context::Make() to return a nullptr. 312 bool finishInitialization(); 313 314 void checkForFinishedWork(SyncToCpu); 315 316 std::unique_ptr<Recorder> makeInternalRecorder() const; 317 318 template <typename SrcPixels> struct AsyncParams; 319 320 template <typename ReadFn, typename... ExtraArgs> 321 void asyncRescaleAndReadImpl(ReadFn Context::* asyncRead, 322 SkImage::RescaleGamma rescaleGamma, 323 SkImage::RescaleMode rescaleMode, 324 const AsyncParams<SkImage>&, 325 ExtraArgs...); 326 327 // Recorder is optional and will be used if drawing operations are required. If no Recorder is 328 // provided but drawing operations are needed, a new Recorder will be created automatically. 329 void asyncReadPixels(std::unique_ptr<Recorder>, const AsyncParams<SkImage>&); 330 void asyncReadPixelsYUV420(std::unique_ptr<Recorder>, 331 const AsyncParams<SkImage>&, 332 SkYUVColorSpace); 333 334 // Like asyncReadPixels() except it performs no fallbacks, and requires that the texture be 335 // readable. However, the texture does not need to be sampleable. 336 void asyncReadTexture(std::unique_ptr<Recorder>, 337 const AsyncParams<TextureProxy>&, 338 const SkColorInfo& srcColorInfo); 339 340 // Inserts a texture to buffer transfer task, used by asyncReadPixels methods. If the 341 // Recorder is non-null, tasks will be added to the Recorder's list; otherwise the transfer 342 // tasks will be added to the queue manager directly. 343 PixelTransferResult transferPixels(Recorder*, 344 const TextureProxy* srcProxy, 345 const SkColorInfo& srcColorInfo, 346 const SkColorInfo& dstColorInfo, 347 const SkIRect& srcRect); 348 349 // If the recorder is non-null, it will be snapped and inserted with the assumption that the 350 // copy tasks (and possibly preparatory draw tasks) have already been added to the Recording. 351 void finalizeAsyncReadPixels(std::unique_ptr<Recorder>, 352 SkSpan<PixelTransferResult>, 353 SkImage::ReadPixelsCallback callback, 354 SkImage::ReadPixelsContext callbackContext); 355 356 sk_sp<SharedContext> fSharedContext; 357 std::unique_ptr<ResourceProvider> fResourceProvider; 358 std::unique_ptr<QueueManager> fQueueManager; 359 std::unique_ptr<ClientMappedBufferManager> fMappedBufferManager; 360 361 // In debug builds we guard against improper thread handling. This guard is passed to the 362 // ResourceCache for the Context. 363 mutable SingleOwner fSingleOwner; 364 365 #if defined(GPU_TEST_UTILS) 366 void deregisterRecorder(const Recorder*) SK_EXCLUDES(fTestingLock); 367 368 // In test builds a Recorder may track the Context that was used to create it. 369 bool fStoreContextRefInRecorder = false; 370 // If this tracking is on, to allow the client to safely delete this Context or its Recorders 371 // in any order we must also track the Recorders created here. 372 SkMutex fTestingLock; 373 std::vector<Recorder*> fTrackedRecorders SK_GUARDED_BY(fTestingLock); 374 #endif 375 376 // Needed for MessageBox handling 377 const ContextID fContextID; 378 }; 379 380 } // namespace skgpu::graphite 381 382 #endif // skgpu_graphite_Context_DEFINED 383