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