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