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