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