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/GrSwizzle.h" 18 19 class GrCaps; 20 class GrContext_Base; 21 class GrRecordingContext; 22 class GrRenderTargetOpList; 23 class GrRenderTargetProxy; 24 class GrRenderTask; 25 class GrResourceProvider; 26 class GrSurfaceContext; 27 class GrSurfaceProxyPriv; 28 class GrTextureOpList; 29 class GrTextureProxy; 30 31 // This is basically SkRefCntBase except Ganesh uses internalGetProxyRefCnt for more than asserts. 32 class GrIORefProxy : public SkNoncopyable { 33 public: GrIORefProxy()34 GrIORefProxy() : fRefCnt(1) {} 35 ~GrIORefProxy()36 virtual ~GrIORefProxy() {} 37 unique()38 bool unique() const { 39 SkASSERT(fRefCnt > 0); 40 return 1 == fRefCnt; 41 } 42 ref()43 void ref() const { 44 SkASSERT(fRefCnt > 0); 45 ++fRefCnt; 46 } 47 unref()48 void unref() const { 49 SkASSERT(fRefCnt > 0); 50 --fRefCnt; 51 if (0 == fRefCnt) { 52 delete this; 53 } 54 } 55 56 protected: internalGetProxyRefCnt()57 int32_t internalGetProxyRefCnt() const { return fRefCnt; } 58 59 private: 60 mutable int32_t fRefCnt; 61 }; 62 63 class GrSurfaceProxy : public GrIORefProxy { 64 public: 65 /** 66 * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return. 67 * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls 68 * the key relationship between proxies and their targets. 69 */ 70 enum class LazyInstantiationKeyMode { 71 /** 72 * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to 73 * return a GrSurface that already has a unique key unrelated to the proxy's key. 74 */ 75 kUnsynced, 76 /** 77 * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface 78 * returned from the lazy instantiation callback must not have a unique key or have the same 79 * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned 80 * to the GrSurface. 81 */ 82 kSynced 83 }; 84 85 struct LazyInstantiationResult { 86 LazyInstantiationResult() = default; 87 LazyInstantiationResult(const LazyInstantiationResult&) = default; 88 LazyInstantiationResult(LazyInstantiationResult&& that) = default; 89 LazyInstantiationResult(sk_sp<GrSurface> surf, 90 LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced) fSurfaceLazyInstantiationResult91 : fSurface(std::move(surf)), fKeyMode(mode) {} LazyInstantiationResultLazyInstantiationResult92 LazyInstantiationResult(sk_sp<GrTexture> tex) 93 : LazyInstantiationResult(sk_sp<GrSurface>(std::move(tex))) {} 94 95 LazyInstantiationResult& operator=(const LazyInstantiationResult&) = default; 96 LazyInstantiationResult& operator=(LazyInstantiationResult&&) = default; 97 98 sk_sp<GrSurface> fSurface; 99 LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced; 100 }; 101 102 using LazyInstantiateCallback = std::function<LazyInstantiationResult(GrResourceProvider*)>; 103 104 enum class LazyInstantiationType { 105 kSingleUse, // Instantiation callback is allowed to be called only once. 106 kMultipleUse, // Instantiation callback can be called multiple times. 107 kDeinstantiate, // Instantiation callback can be called multiple times, 108 // but we will deinstantiate the proxy after every flush. 109 }; 110 111 enum class LazyState { 112 kNot, // The proxy is instantiated or does not have a lazy callback 113 kPartially, // The proxy has a lazy callback but knows basic information about itself. 114 kFully, // The proxy has a lazy callback and also doesn't know its width, height, etc. 115 }; 116 lazyInstantiationState()117 LazyState lazyInstantiationState() const { 118 if (this->isInstantiated() || !SkToBool(fLazyInstantiateCallback)) { 119 return LazyState::kNot; 120 } else { 121 if (fWidth <= 0) { 122 SkASSERT(fHeight <= 0); 123 return LazyState::kFully; 124 } else { 125 SkASSERT(fHeight > 0); 126 return LazyState::kPartially; 127 } 128 } 129 } 130 config()131 GrPixelConfig config() const { return fConfig; } width()132 int width() const { 133 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 134 return fWidth; 135 } height()136 int height() const { 137 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 138 return fHeight; 139 } 140 isize()141 SkISize isize() const { return {fWidth, fHeight}; } 142 143 int worstCaseWidth() const; 144 int worstCaseHeight() const; 145 /** 146 * Helper that gets the width and height of the surface as a bounding rectangle. 147 */ getBoundsRect()148 SkRect getBoundsRect() const { 149 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 150 return SkRect::MakeIWH(this->width(), this->height()); 151 } 152 /** 153 * Helper that gets the worst case width and height of the surface as a bounding rectangle. 154 */ getWorstCaseBoundsRect()155 SkRect getWorstCaseBoundsRect() const { 156 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 157 return SkRect::MakeIWH(this->worstCaseWidth(), this->worstCaseHeight()); 158 } 159 origin()160 GrSurfaceOrigin origin() const { 161 SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin); 162 return fOrigin; 163 } 164 textureSwizzle()165 const GrSwizzle& textureSwizzle() const { return fTextureSwizzle; } 166 backendFormat()167 const GrBackendFormat& backendFormat() const { return fFormat; } 168 169 class UniqueID { 170 public: InvalidID()171 static UniqueID InvalidID() { 172 return UniqueID(uint32_t(SK_InvalidUniqueID)); 173 } 174 175 // wrapped UniqueID(const GrGpuResource::UniqueID & id)176 explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } 177 // deferred and lazy-callback UniqueID()178 UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } 179 asUInt()180 uint32_t asUInt() const { return fID; } 181 182 bool operator==(const UniqueID& other) const { 183 return fID == other.fID; 184 } 185 bool operator!=(const UniqueID& other) const { 186 return !(*this == other); 187 } 188 makeInvalid()189 void makeInvalid() { fID = SK_InvalidUniqueID; } isInvalid()190 bool isInvalid() const { return SK_InvalidUniqueID == fID; } 191 192 private: UniqueID(uint32_t id)193 explicit UniqueID(uint32_t id) : fID(id) {} 194 195 uint32_t fID; 196 }; 197 198 /* 199 * The contract for the uniqueID is: 200 * for wrapped resources: 201 * the uniqueID will match that of the wrapped resource 202 * 203 * for deferred resources: 204 * the uniqueID will be different from the real resource, when it is allocated 205 * the proxy's uniqueID will not change across the instantiate call 206 * 207 * the uniqueIDs of the proxies and the resources draw from the same pool 208 * 209 * What this boils down to is that the uniqueID of a proxy can be used to consistently 210 * track/identify a proxy but should never be used to distinguish between 211 * resources and proxies - beware! 212 */ uniqueID()213 UniqueID uniqueID() const { return fUniqueID; } 214 underlyingUniqueID()215 UniqueID underlyingUniqueID() const { 216 if (fTarget) { 217 return UniqueID(fTarget->uniqueID()); 218 } 219 220 return fUniqueID; 221 } 222 223 virtual bool instantiate(GrResourceProvider*) = 0; 224 225 void deinstantiate(); 226 227 /** 228 * Proxies that are already instantiated and whose backing surface cannot be recycled to 229 * instantiate other proxies do not need to be considered by GrResourceAllocator. 230 */ 231 bool canSkipResourceAllocator() const; 232 233 /** 234 * @return the texture proxy associated with the surface proxy, may be NULL. 235 */ asTextureProxy()236 virtual GrTextureProxy* asTextureProxy() { return nullptr; } asTextureProxy()237 virtual const GrTextureProxy* asTextureProxy() const { return nullptr; } 238 239 /** 240 * @return the render target proxy associated with the surface proxy, may be NULL. 241 */ asRenderTargetProxy()242 virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; } asRenderTargetProxy()243 virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; } 244 isInstantiated()245 bool isInstantiated() const { return SkToBool(fTarget); } 246 247 // If the proxy is already instantiated, return its backing GrTexture; if not, return null. peekSurface()248 GrSurface* peekSurface() const { return fTarget.get(); } 249 250 // If this is a texture proxy and the proxy is already instantiated, return its backing 251 // GrTexture; if not, return null. peekTexture()252 GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; } 253 254 // If this is a render target proxy and the proxy is already instantiated, return its backing 255 // GrRenderTarget; if not, return null. peekRenderTarget()256 GrRenderTarget* peekRenderTarget() const { 257 return fTarget ? fTarget->asRenderTarget() : nullptr; 258 } 259 260 /** 261 * Does the resource count against the resource budget? 262 */ isBudgeted()263 SkBudgeted isBudgeted() const { return fBudgeted; } 264 265 /** 266 * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write 267 * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and 268 * assignment in GrResourceAllocator. 269 */ readOnly()270 bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; } 271 272 void setLastRenderTask(GrRenderTask*); getLastRenderTask()273 GrRenderTask* getLastRenderTask() { return fLastRenderTask; } 274 275 GrRenderTargetOpList* getLastRenderTargetOpList(); 276 GrTextureOpList* getLastTextureOpList(); 277 278 /** 279 * Retrieves the amount of GPU memory that will be or currently is used by this resource 280 * in bytes. It is approximate since we aren't aware of additional padding or copies made 281 * by the driver. 282 * 283 * @return the amount of GPU memory used in bytes 284 */ gpuMemorySize()285 size_t gpuMemorySize() const { 286 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 287 if (fTarget) { 288 return fTarget->gpuMemorySize(); 289 } 290 if (kInvalidGpuMemorySize == fGpuMemorySize) { 291 fGpuMemorySize = this->onUninstantiatedGpuMemorySize(); 292 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 293 } 294 return fGpuMemorySize; 295 } 296 297 enum class RectsMustMatch : bool { 298 kNo = false, 299 kYes = true 300 }; 301 302 // Helper function that creates a temporary SurfaceContext to perform the copy 303 // The copy is is not a render target and not multisampled. 304 static sk_sp<GrTextureProxy> Copy(GrRecordingContext*, GrSurfaceProxy* src, GrMipMapped, 305 SkIRect srcRect, SkBackingFit, SkBudgeted, 306 RectsMustMatch = RectsMustMatch::kNo); 307 308 // Copy the entire 'src' 309 static sk_sp<GrTextureProxy> Copy(GrRecordingContext*, GrSurfaceProxy* src, GrMipMapped, 310 SkBackingFit, SkBudgeted); 311 312 #if GR_TEST_UTILS 313 int32_t testingOnly_getBackingRefCnt() const; 314 GrInternalSurfaceFlags testingOnly_getFlags() const; 315 #endif 316 317 SkDEBUGCODE(void validate(GrContext_Base*) const;) 318 319 // Provides access to functions that aren't part of the public API. 320 inline GrSurfaceProxyPriv priv(); 321 inline const GrSurfaceProxyPriv priv() const; 322 323 // Returns true if we are working with protected content. isProtected()324 bool isProtected() const { return fIsProtected == GrProtected::kYes; } 325 326 protected: 327 // Deferred version GrSurfaceProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrRenderable renderable,GrSurfaceOrigin origin,const GrSwizzle & textureSwizzle,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags)328 GrSurfaceProxy(const GrBackendFormat& format, const GrSurfaceDesc& desc, 329 GrRenderable renderable, GrSurfaceOrigin origin, const GrSwizzle& textureSwizzle, 330 SkBackingFit fit, SkBudgeted budgeted, GrProtected isProtected, 331 GrInternalSurfaceFlags surfaceFlags) 332 : GrSurfaceProxy(nullptr, LazyInstantiationType::kSingleUse, format, desc, renderable, 333 origin, textureSwizzle, fit, budgeted, isProtected, surfaceFlags) { 334 // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources 335 } 336 337 // Lazy-callback version 338 GrSurfaceProxy(LazyInstantiateCallback&&, LazyInstantiationType, const GrBackendFormat& format, 339 const GrSurfaceDesc&, GrRenderable, GrSurfaceOrigin, 340 const GrSwizzle& textureSwizzle, SkBackingFit, SkBudgeted, GrProtected, 341 GrInternalSurfaceFlags); 342 343 // Wrapped version. 344 GrSurfaceProxy(sk_sp<GrSurface>, GrSurfaceOrigin, const GrSwizzle& textureSwizzle, 345 SkBackingFit); 346 347 ~GrSurfaceProxy() override; 348 349 friend class GrSurfaceProxyPriv; 350 351 // Methods made available via GrSurfaceProxyPriv ignoredByResourceAllocator()352 bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; } setIgnoredByResourceAllocator()353 void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; } 354 getProxyRefCnt()355 int32_t getProxyRefCnt() const { return this->internalGetProxyRefCnt(); } 356 357 void computeScratchKey(GrScratchKey*) const; 358 359 virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0; 360 void assign(sk_sp<GrSurface> surface); 361 362 sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, 363 int minStencilSampleCount, GrRenderable, GrMipMapped) const; 364 365 // Once the size of a fully-lazy proxy is decided, and before it gets instantiated, the client 366 // can use this optional method to specify the proxy's size. (A proxy's size can be less than 367 // the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise, the proxy's size will 368 // be set to match the underlying GPU surface upon instantiation. setLazySize(int width,int height)369 void setLazySize(int width, int height) { 370 SkASSERT(GrSurfaceProxy::LazyState::kFully == this->lazyInstantiationState()); 371 SkASSERT(width > 0 && height > 0); 372 fWidth = width; 373 fHeight = height; 374 } 375 376 bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, 377 int minStencilSampleCount, GrRenderable, GrMipMapped, const GrUniqueKey*); 378 379 // For deferred proxies this will be null until the proxy is instantiated. 380 // For wrapped proxies it will point to the wrapped resource. 381 sk_sp<GrSurface> fTarget; 382 383 // In many cases these flags aren't actually known until the proxy has been instantiated. 384 // However, Ganesh frequently needs to change its behavior based on these settings. For 385 // internally create proxies we will know these properties ahead of time. For wrapped 386 // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the 387 // call sites to provide the required information ahead of time. At instantiation time 388 // we verify that the assumed properties match the actual properties. 389 GrInternalSurfaceFlags fSurfaceFlags; 390 391 private: 392 // For wrapped resources, 'fFormat', 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always 393 // be filled in from the wrapped resource. 394 GrBackendFormat fFormat; 395 GrPixelConfig fConfig; 396 int fWidth; 397 int fHeight; 398 GrSurfaceOrigin fOrigin; 399 GrSwizzle fTextureSwizzle; 400 401 SkBackingFit fFit; // always kApprox for lazy-callback resources 402 // always kExact for wrapped resources 403 mutable SkBudgeted fBudgeted; // always kYes for lazy-callback resources 404 // set from the backing resource for wrapped resources 405 // mutable bc of SkSurface/SkImage wishy-washiness 406 407 const UniqueID fUniqueID; // set from the backing resource for wrapped resources 408 409 LazyInstantiateCallback fLazyInstantiateCallback; 410 // If this is set to kSingleuse, then after one call to fLazyInstantiateCallback we will cleanup 411 // the lazy callback and then delete it. This will allow for any refs and resources being held 412 // by the standard function to be released. This is specifically useful in non-dll cases where 413 // we make lazy proxies and instantiate them immediately. 414 // Note: This is ignored if fLazyInstantiateCallback is null. 415 LazyInstantiationType fLazyInstantiationType; 416 417 SkDEBUGCODE(void validateSurface(const GrSurface*);) 418 SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;) 419 420 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 421 SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) 422 423 virtual size_t onUninstantiatedGpuMemorySize() const = 0; 424 425 bool fIgnoredByResourceAllocator = false; 426 GrProtected fIsProtected; 427 428 // This entry is lazily evaluated so, when the proxy wraps a resource, the resource 429 // will be called but, when the proxy is deferred, it will compute the answer itself. 430 // If the proxy computes its own answer that answer is checked (in debug mode) in 431 // the instantiation method. 432 mutable size_t fGpuMemorySize; 433 434 // The last opList that wrote to or is currently going to write to this surface 435 // The opList can be closed (e.g., no surface context is currently bound 436 // to this proxy). 437 // This back-pointer is required so that we can add a dependancy between 438 // the opList used to create the current contents of this surface 439 // and the opList of a destination surface to which this one is being drawn or copied. 440 // This pointer is unreffed. GrRenderTasks own a ref on their surface proxies. 441 GrRenderTask* fLastRenderTask; 442 443 typedef GrIORefProxy INHERITED; 444 }; 445 446 #endif 447