1 /* 2 * Copyright 2016 Google Inc. 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 GrSurfaceProxy_DEFINED 9 #define GrSurfaceProxy_DEFINED 10 11 #include "include/core/SkRect.h" 12 #include "include/core/SkRefCnt.h" 13 #include "include/core/SkSize.h" 14 #include "include/core/SkString.h" 15 #include "include/core/SkTypes.h" 16 #include "include/gpu/GrBackendSurface.h" 17 #include "include/gpu/GrTypes.h" 18 #include "include/private/base/SkDebug.h" 19 #include "include/private/base/SkTo.h" 20 #include "include/private/gpu/ganesh/GrTypesPriv.h" 21 #include "src/gpu/ResourceKey.h" 22 #include "src/gpu/ganesh/GrGpuResource.h" 23 #include "src/gpu/ganesh/GrSurface.h" 24 25 #include <atomic> 26 #include <cstddef> 27 #include <cstdint> 28 #include <functional> 29 #include <string> 30 #include <string_view> 31 #include <utility> 32 33 class GrCaps; 34 class GrContext_Base; 35 class GrRecordingContext; 36 class GrRenderTarget; 37 class GrRenderTargetProxy; 38 class GrRenderTask; 39 class GrResourceProvider; 40 class GrSurfaceProxyPriv; 41 class GrTexture; 42 class GrTextureProxy; 43 enum class SkBackingFit; 44 namespace skgpu { 45 enum class Budgeted : bool; 46 enum class Mipmapped : bool; 47 } 48 49 class GrSurfaceProxy : public SkNVRefCnt<GrSurfaceProxy> { 50 public: 51 virtual ~GrSurfaceProxy(); 52 53 /** 54 * Indicates "resolutions" that need to be done on a surface before its pixels can be accessed. 55 * If both types of resolve are requested, the MSAA resolve will happen first. 56 */ 57 enum class ResolveFlags { 58 kNone = 0, 59 kMSAA = 1 << 0, // Blit and resolve an internal MSAA render buffer into the texture. 60 kMipMaps = 1 << 1, // Regenerate all mipmap levels. 61 }; 62 63 /** 64 * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return. 65 * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls 66 * the key relationship between proxies and their targets. 67 */ 68 enum class LazyInstantiationKeyMode { 69 /** 70 * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to 71 * return a GrSurface that already has a unique key unrelated to the proxy's key. 72 */ 73 kUnsynced, 74 /** 75 * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface 76 * returned from the lazy instantiation callback must not have a unique key or have the same 77 * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned 78 * to the GrSurface. 79 */ 80 kSynced 81 }; 82 83 /** 84 * Specifies the expected properties of the GrSurface returned by a lazy instantiation 85 * callback. The dimensions will be negative in the case of a fully lazy proxy. 86 */ 87 struct LazySurfaceDesc { 88 SkISize fDimensions; 89 SkBackingFit fFit; 90 GrRenderable fRenderable; 91 skgpu::Mipmapped fMipmapped; 92 int fSampleCnt; 93 const GrBackendFormat& fFormat; 94 GrTextureType fTextureType; 95 GrProtected fProtected; 96 skgpu::Budgeted fBudgeted; 97 std::string_view fLabel; 98 }; 99 100 struct LazyCallbackResult { 101 LazyCallbackResult() = default; 102 LazyCallbackResult(const LazyCallbackResult&) = default; 103 LazyCallbackResult(LazyCallbackResult&& that) = default; 104 LazyCallbackResult(sk_sp<GrSurface> surf, 105 bool releaseCallback = true, 106 LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced); 107 LazyCallbackResult(sk_sp<GrTexture> tex); 108 109 LazyCallbackResult& operator=(const LazyCallbackResult&) = default; 110 LazyCallbackResult& operator=(LazyCallbackResult&&) = default; 111 112 sk_sp<GrSurface> fSurface; 113 LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced; 114 /** 115 * Should the callback be disposed of after it has returned or preserved until the proxy 116 * is freed. Only honored if fSurface is not-null. If it is null the callback is preserved. 117 */ 118 bool fReleaseCallback = true; 119 }; 120 121 using LazyInstantiateCallback = 122 std::function<LazyCallbackResult(GrResourceProvider*, const LazySurfaceDesc&)>; 123 124 enum class UseAllocator { 125 /** 126 * This proxy will be instantiated outside the allocator (e.g. for proxies that are 127 * instantiated in on-flush callbacks). 128 */ 129 kNo = false, 130 /** 131 * GrResourceAllocator should instantiate this proxy. 132 */ 133 kYes = true, 134 }; 135 isLazy()136 bool isLazy() const { return !this->isInstantiated() && SkToBool(fLazyInstantiateCallback); } 137 isFullyLazy()138 bool isFullyLazy() const { 139 bool result = fDimensions.width() < 0; 140 SkASSERT(result == (fDimensions.height() < 0)); 141 SkASSERT(!result || this->isLazy()); 142 return result; 143 } 144 dimensions()145 SkISize dimensions() const { 146 SkASSERT(!this->isFullyLazy()); 147 return fDimensions; 148 } width()149 int width() const { return this->dimensions().width(); } height()150 int height() const { return this->dimensions().height(); } 151 152 SkISize backingStoreDimensions() const; 153 154 /** 155 * Helper that gets the width and height of the proxy as a bounding rectangle. 156 */ getBoundsRect()157 SkRect getBoundsRect() const { return SkRect::Make(this->dimensions()); } 158 159 /* A perhaps faster check for this->dimensions() == this->backingStoreDimensions(). */ 160 bool isFunctionallyExact() const; 161 162 /** 163 * Helper that gets the dimensions the backing GrSurface will have as a bounding rectangle. 164 */ backingStoreBoundsRect()165 SkRect backingStoreBoundsRect() const { 166 return SkRect::Make(this->backingStoreDimensions()); 167 } 168 backingStoreBoundsIRect()169 SkIRect backingStoreBoundsIRect() const { 170 return SkIRect::MakeSize(this->backingStoreDimensions()); 171 } 172 backendFormat()173 const GrBackendFormat& backendFormat() const { return fFormat; } 174 175 bool isFormatCompressed(const GrCaps*) const; 176 177 class UniqueID { 178 public: InvalidID()179 static UniqueID InvalidID() { 180 return UniqueID(uint32_t(SK_InvalidUniqueID)); 181 } 182 183 // wrapped UniqueID(const GrGpuResource::UniqueID & id)184 explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } 185 // deferred and lazy-callback UniqueID()186 UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } 187 asUInt()188 uint32_t asUInt() const { return fID; } 189 190 bool operator==(const UniqueID& other) const { 191 return fID == other.fID; 192 } 193 bool operator!=(const UniqueID& other) const { 194 return !(*this == other); 195 } 196 makeInvalid()197 void makeInvalid() { fID = SK_InvalidUniqueID; } isInvalid()198 bool isInvalid() const { return SK_InvalidUniqueID == fID; } 199 200 private: UniqueID(uint32_t id)201 explicit UniqueID(uint32_t id) : fID(id) {} 202 203 uint32_t fID; 204 }; 205 206 /* 207 * The contract for the uniqueID is: 208 * for wrapped resources: 209 * the uniqueID will match that of the wrapped resource 210 * 211 * for deferred resources: 212 * the uniqueID will be different from the real resource, when it is allocated 213 * the proxy's uniqueID will not change across the instantiate call 214 * 215 * the uniqueIDs of the proxies and the resources draw from the same pool 216 * 217 * What this boils down to is that the uniqueID of a proxy can be used to consistently 218 * track/identify a proxy but should never be used to distinguish between 219 * resources and proxies - beware! 220 */ uniqueID()221 UniqueID uniqueID() const { return fUniqueID; } 222 underlyingUniqueID()223 UniqueID underlyingUniqueID() const { 224 if (fTarget) { 225 return UniqueID(fTarget->uniqueID()); 226 } 227 228 return fUniqueID; 229 } 230 231 virtual bool instantiate(GrResourceProvider*) = 0; 232 233 void deinstantiate(); 234 235 /** 236 * Proxies that are already instantiated and whose backing surface cannot be recycled to 237 * instantiate other proxies do not need to be considered by GrResourceAllocator. 238 */ 239 bool canSkipResourceAllocator() const; 240 241 /** 242 * @return the texture proxy associated with the surface proxy, may be NULL. 243 */ asTextureProxy()244 virtual GrTextureProxy* asTextureProxy() { return nullptr; } asTextureProxy()245 virtual const GrTextureProxy* asTextureProxy() const { return nullptr; } 246 247 /** 248 * @return the render target proxy associated with the surface proxy, may be NULL. 249 */ asRenderTargetProxy()250 virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; } asRenderTargetProxy()251 virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; } 252 253 /** @return The unique key for this proxy. May be invalid. */ getUniqueKey()254 virtual const skgpu::UniqueKey& getUniqueKey() const { 255 // Base class never has a valid unique key. 256 static const skgpu::UniqueKey kInvalidKey; 257 return kInvalidKey; 258 } 259 isInstantiated()260 bool isInstantiated() const { return SkToBool(fTarget); } 261 262 /** Called when this task becomes a target of a GrRenderTask. */ isUsedAsTaskTarget()263 void isUsedAsTaskTarget() { ++fTaskTargetCount; } 264 265 /** How many render tasks has this proxy been the target of? */ getTaskTargetCount()266 int getTaskTargetCount() const { return fTaskTargetCount; } 267 268 // If the proxy is already instantiated, return its backing GrTexture; if not, return null. peekSurface()269 GrSurface* peekSurface() const { return fTarget.get(); } 270 271 // If this is a texture proxy and the proxy is already instantiated, return its backing 272 // GrTexture; if not, return null. peekTexture()273 GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; } 274 275 // If this is a render target proxy and the proxy is already instantiated, return its backing 276 // GrRenderTarget; if not, return null. peekRenderTarget()277 GrRenderTarget* peekRenderTarget() const { 278 return fTarget ? fTarget->asRenderTarget() : nullptr; 279 } 280 281 /** 282 * Does the resource count against the resource budget? 283 */ isBudgeted()284 skgpu::Budgeted isBudgeted() const { return fBudgeted; } 285 286 /** 287 * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write 288 * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and 289 * assignment in GrResourceAllocator. 290 */ readOnly()291 bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; } framebufferOnly()292 bool framebufferOnly() const { 293 return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly; 294 } 295 296 /** 297 * This means surface is a multisampled render target, and internally holds a non-msaa texture 298 * for resolving into. The render target resolves itself by blitting into this internal texture. 299 * (asTexture() might or might not return the internal texture, but if it does, we always 300 * resolve the render target before accessing this texture's data.) 301 */ requiresManualMSAAResolve()302 bool requiresManualMSAAResolve() const { 303 return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve; 304 } 305 306 /** 307 * Retrieves the amount of GPU memory that will be or currently is used by this resource 308 * in bytes. It is approximate since we aren't aware of additional padding or copies made 309 * by the driver. 310 * 311 * @return the amount of GPU memory used in bytes 312 */ gpuMemorySize()313 size_t gpuMemorySize() const { 314 SkASSERT(!this->isFullyLazy()); 315 if (kInvalidGpuMemorySize == fGpuMemorySize) { 316 fGpuMemorySize = this->onUninstantiatedGpuMemorySize(); 317 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 318 } 319 return fGpuMemorySize; 320 } 321 getLabel()322 std::string_view getLabel() const { return fLabel; } 323 324 enum class RectsMustMatch : bool { 325 kNo = false, 326 kYes = true 327 }; 328 329 // Helper function that creates a temporary SurfaceContext to perform the copy 330 // The copy is is not a render target and not multisampled. 331 // 332 // The intended use of this copy call is simply to copy exact pixel values from one proxy to a 333 // new one. Thus, there isn't a need for a swizzle when doing the copy. The format of the copy 334 // will be the same as the src. Therefore, the copy can be used in a view with the same swizzle 335 // as the original for use with a given color type. 336 // 337 // Optionally gets the render task that performs the copy. If it is later determined that the 338 // copy is not neccessaru then the task can be marked skippable using GrRenderTask::canSkip() and 339 // the copy will be elided. 340 static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*, 341 sk_sp<GrSurfaceProxy> src, 342 GrSurfaceOrigin, 343 skgpu::Mipmapped, 344 SkIRect srcRect, 345 SkBackingFit, 346 skgpu::Budgeted, 347 std::string_view label, 348 RectsMustMatch = RectsMustMatch::kNo, 349 sk_sp<GrRenderTask>* outTask = nullptr); 350 351 // Same as above Copy but copies the entire 'src' 352 static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*, 353 sk_sp<GrSurfaceProxy> src, 354 GrSurfaceOrigin, 355 skgpu::Mipmapped, 356 SkBackingFit, 357 skgpu::Budgeted, 358 std::string_view label, 359 sk_sp<GrRenderTask>* outTask = nullptr); 360 361 #if defined(GR_TEST_UTILS) 362 int32_t testingOnly_getBackingRefCnt() const; 363 GrInternalSurfaceFlags testingOnly_getFlags() const; 364 SkString dump() const; 365 #endif 366 367 #ifdef SK_DEBUG 368 void validate(GrContext_Base*) const; getDebugName()369 SkString getDebugName() { 370 return fDebugName.isEmpty() ? SkStringPrintf("%u", this->uniqueID().asUInt()) : fDebugName; 371 } setDebugName(SkString name)372 void setDebugName(SkString name) { fDebugName = std::move(name); } 373 #endif 374 375 // Provides access to functions that aren't part of the public API. 376 inline GrSurfaceProxyPriv priv(); 377 inline const GrSurfaceProxyPriv priv() const; // NOLINT(readability-const-return-type) 378 isDDLTarget()379 bool isDDLTarget() const { return fIsDDLTarget; } 380 isProtected()381 GrProtected isProtected() const { return fIsProtected; } 382 isPromiseProxy()383 bool isPromiseProxy() { return fIsPromiseProxy; } 384 385 protected: 386 // Deferred version - takes a new UniqueID from the shared resource/proxy pool. 387 GrSurfaceProxy(const GrBackendFormat&, 388 SkISize, 389 SkBackingFit, 390 skgpu::Budgeted, 391 GrProtected, 392 GrInternalSurfaceFlags, 393 UseAllocator, 394 std::string_view label); 395 // Lazy-callback version - takes a new UniqueID from the shared resource/proxy pool. 396 GrSurfaceProxy(LazyInstantiateCallback&&, 397 const GrBackendFormat&, 398 SkISize, 399 SkBackingFit, 400 skgpu::Budgeted, 401 GrProtected, 402 GrInternalSurfaceFlags, 403 UseAllocator, 404 std::string_view label); 405 406 // Wrapped version - shares the UniqueID of the passed surface. 407 // Takes UseAllocator because even though this is already instantiated it still can participate 408 // in allocation by having its backing resource recycled to other uninstantiated proxies or 409 // not depending on UseAllocator. 410 GrSurfaceProxy(sk_sp<GrSurface>, SkBackingFit, UseAllocator); 411 412 friend class GrSurfaceProxyPriv; 413 414 // Methods made available via GrSurfaceProxyPriv ignoredByResourceAllocator()415 bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; } setIgnoredByResourceAllocator()416 void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; } 417 418 void computeScratchKey(const GrCaps&, skgpu::ScratchKey*) const; 419 420 virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0; 421 void assign(sk_sp<GrSurface> surface); 422 423 sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, 424 int sampleCnt, 425 GrRenderable, 426 skgpu::Mipmapped) const; 427 428 // Once the dimensions of a fully-lazy proxy are decided, and before it gets instantiated, the 429 // client can use this optional method to specify the proxy's dimensions. (A proxy's dimensions 430 // can be less than the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise, 431 // the proxy's dimensions will be set to match the underlying GPU surface upon instantiation. setLazyDimensions(SkISize dimensions)432 void setLazyDimensions(SkISize dimensions) { 433 SkASSERT(this->isFullyLazy()); 434 SkASSERT(!dimensions.isEmpty()); 435 fDimensions = dimensions; 436 } 437 438 bool instantiateImpl(GrResourceProvider* resourceProvider, 439 int sampleCnt, 440 GrRenderable, 441 skgpu::Mipmapped, 442 const skgpu::UniqueKey*); 443 444 // For deferred proxies this will be null until the proxy is instantiated. 445 // For wrapped proxies it will point to the wrapped resource. 446 sk_sp<GrSurface> fTarget; 447 448 // In many cases these flags aren't actually known until the proxy has been instantiated. 449 // However, Ganesh frequently needs to change its behavior based on these settings. For 450 // internally create proxies we will know these properties ahead of time. For wrapped 451 // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the 452 // call sites to provide the required information ahead of time. At instantiation time 453 // we verify that the assumed properties match the actual properties. 454 GrInternalSurfaceFlags fSurfaceFlags; 455 456 private: 457 // For wrapped resources, 'fFormat' and 'fDimensions' will always be filled in from the 458 // wrapped resource. 459 const GrBackendFormat fFormat; 460 SkISize fDimensions; 461 462 SkBackingFit fFit; // always kApprox for lazy-callback resources 463 // always kExact for wrapped resources 464 mutable skgpu::Budgeted fBudgeted; // always kYes for lazy-callback resources 465 // set from the backing resource for wrapped resources 466 // mutable bc of SkSurface/SkImage wishy-washiness 467 // Only meaningful if fLazyInstantiateCallback is non-null. 468 UseAllocator fUseAllocator; 469 470 const UniqueID fUniqueID; // set from the backing resource for wrapped resources 471 472 LazyInstantiateCallback fLazyInstantiateCallback; 473 474 SkDEBUGCODE(void validateSurface(const GrSurface*);) 475 SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;) 476 477 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 478 SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) 479 480 virtual size_t onUninstantiatedGpuMemorySize() const = 0; 481 482 virtual LazySurfaceDesc callbackDesc() const = 0; 483 484 bool fIgnoredByResourceAllocator = false; 485 bool fIsDDLTarget = false; 486 bool fIsPromiseProxy = false; 487 GrProtected fIsProtected; 488 489 int fTaskTargetCount = 0; 490 491 const std::string fLabel; 492 493 // This entry is lazily evaluated so, when the proxy wraps a resource, the resource 494 // will be called but, when the proxy is deferred, it will compute the answer itself. 495 // If the proxy computes its own answer that answer is checked (in debug mode) in 496 // the instantiation method. The image may be shared between threads, hence atomic. 497 mutable std::atomic<size_t> fGpuMemorySize{kInvalidGpuMemorySize}; 498 SkDEBUGCODE(SkString fDebugName;) 499 }; 500 501 GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags) 502 503 #endif 504