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