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 "GrGpuResource.h" 12 #include "GrSurface.h" 13 14 #include "SkRect.h" 15 16 class GrBackendTexture; 17 class GrCaps; 18 class GrOpList; 19 class GrRenderTargetOpList; 20 class GrRenderTargetProxy; 21 class GrResourceProvider; 22 class GrSurfaceContext; 23 class GrSurfaceProxyPriv; 24 class GrTextureOpList; 25 class GrTextureProxy; 26 27 // This class replicates the functionality GrIORef<GrSurface> but tracks the 28 // utilitization for later resource allocation (for the deferred case) and 29 // forwards on the utilization in the wrapped case 30 class GrIORefProxy : public SkNoncopyable { 31 public: ref()32 void ref() const { 33 this->validate(); 34 35 ++fRefCnt; 36 if (fTarget) { 37 fTarget->ref(); 38 } 39 } 40 unref()41 void unref() const { 42 this->validate(); 43 44 if (fTarget) { 45 fTarget->unref(); 46 } 47 48 --fRefCnt; 49 this->didRemoveRefOrPendingIO(); 50 } 51 validate()52 void validate() const { 53 #ifdef SK_DEBUG 54 SkASSERT(fRefCnt >= 0); 55 SkASSERT(fPendingReads >= 0); 56 SkASSERT(fPendingWrites >= 0); 57 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1); 58 59 if (fTarget) { 60 // The backing GrSurface can have more refs than the proxy if the proxy 61 // started off wrapping an external resource (that came in with refs). 62 // The GrSurface should never have fewer refs than the proxy however. 63 SkASSERT(fTarget->fRefCnt >= fRefCnt); 64 SkASSERT(fTarget->fPendingReads >= fPendingReads); 65 SkASSERT(fTarget->fPendingWrites >= fPendingWrites); 66 } 67 #endif 68 } 69 70 int32_t getProxyRefCnt_TestOnly() const; 71 int32_t getBackingRefCnt_TestOnly() const; 72 int32_t getPendingReadCnt_TestOnly() const; 73 int32_t getPendingWriteCnt_TestOnly() const; 74 75 protected: GrIORefProxy()76 GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {} GrIORefProxy(sk_sp<GrSurface> surface)77 GrIORefProxy(sk_sp<GrSurface> surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { 78 // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing 79 // anything extra. 80 fTarget = surface.release(); 81 } ~GrIORefProxy()82 virtual ~GrIORefProxy() { 83 // We don't unref 'fTarget' here since the 'unref' method will already 84 // have forwarded on the unref call that got use here. 85 } 86 87 // This GrIORefProxy was deferred before but has just been instantiated. To 88 // make all the reffing & unreffing work out we now need to transfer any deferred 89 // refs & unrefs to the new GrSurface transferRefs()90 void transferRefs() { 91 SkASSERT(fTarget); 92 93 fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref 94 fTarget->fPendingReads += fPendingReads; 95 fTarget->fPendingWrites += fPendingWrites; 96 } 97 internalHasPendingIO()98 bool internalHasPendingIO() const { 99 if (fTarget) { 100 return fTarget->internalHasPendingIO(); 101 } 102 103 return SkToBool(fPendingWrites | fPendingReads); 104 } 105 internalHasPendingWrite()106 bool internalHasPendingWrite() const { 107 if (fTarget) { 108 return fTarget->internalHasPendingWrite(); 109 } 110 111 return SkToBool(fPendingWrites); 112 } 113 114 // For deferred proxies this will be null. For wrapped proxies it will point to the 115 // wrapped resource. 116 GrSurface* fTarget; 117 118 private: 119 // This class is used to manage conversion of refs to pending reads/writes. 120 friend class GrSurfaceProxyRef; 121 template <typename, GrIOType> friend class GrPendingIOResource; 122 addPendingRead()123 void addPendingRead() const { 124 this->validate(); 125 126 ++fPendingReads; 127 if (fTarget) { 128 fTarget->addPendingRead(); 129 } 130 } 131 completedRead()132 void completedRead() const { 133 this->validate(); 134 135 if (fTarget) { 136 fTarget->completedRead(); 137 } 138 139 --fPendingReads; 140 this->didRemoveRefOrPendingIO(); 141 } 142 addPendingWrite()143 void addPendingWrite() const { 144 this->validate(); 145 146 ++fPendingWrites; 147 if (fTarget) { 148 fTarget->addPendingWrite(); 149 } 150 } 151 completedWrite()152 void completedWrite() const { 153 this->validate(); 154 155 if (fTarget) { 156 fTarget->completedWrite(); 157 } 158 159 --fPendingWrites; 160 this->didRemoveRefOrPendingIO(); 161 } 162 didRemoveRefOrPendingIO()163 void didRemoveRefOrPendingIO() const { 164 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { 165 delete this; 166 } 167 } 168 169 mutable int32_t fRefCnt; 170 mutable int32_t fPendingReads; 171 mutable int32_t fPendingWrites; 172 }; 173 174 class GrSurfaceProxy : public GrIORefProxy { 175 public: 176 static sk_sp<GrSurfaceProxy> MakeWrapped(sk_sp<GrSurface>); 177 static sk_sp<GrTextureProxy> MakeWrapped(sk_sp<GrTexture>); 178 179 static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*, 180 const GrSurfaceDesc&, SkBackingFit, 181 SkBudgeted, uint32_t flags = 0); 182 183 /** 184 * Creates a proxy that will be mipmapped. 185 * 186 * @param desc Description of the texture properties. 187 * @param budgeted Does the texture count against the resource cache budget? 188 * @param texels A contiguous array of mipmap levels 189 * @param mipLevelCount The amount of elements in the texels array 190 */ 191 static sk_sp<GrTextureProxy> MakeDeferredMipMap(GrResourceProvider*, 192 const GrSurfaceDesc& desc, SkBudgeted budgeted, 193 const GrMipLevel texels[], int mipLevelCount, 194 SkDestinationSurfaceColorMode mipColorMode = 195 SkDestinationSurfaceColorMode::kLegacy); 196 197 // TODO: need to refine ownership semantics of 'srcData' if we're in completely 198 // deferred mode 199 static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*, 200 const GrSurfaceDesc&, SkBudgeted, 201 const void* srcData, size_t rowBytes); 202 203 static sk_sp<GrTextureProxy> MakeWrappedBackend(GrContext*, GrBackendTexture&, GrSurfaceOrigin); 204 origin()205 GrSurfaceOrigin origin() const { 206 SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin); 207 return fOrigin; 208 } width()209 int width() const { return fWidth; } height()210 int height() const { return fHeight; } config()211 GrPixelConfig config() const { return fConfig; } 212 213 class UniqueID { 214 public: InvalidID()215 static UniqueID InvalidID() { 216 return UniqueID(uint32_t(SK_InvalidUniqueID)); 217 } 218 219 // wrapped UniqueID(const GrGpuResource::UniqueID & id)220 explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } 221 // deferred UniqueID()222 UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } 223 asUInt()224 uint32_t asUInt() const { return fID; } 225 226 bool operator==(const UniqueID& other) const { 227 return fID == other.fID; 228 } 229 bool operator!=(const UniqueID& other) const { 230 return !(*this == other); 231 } 232 makeInvalid()233 void makeInvalid() { fID = SK_InvalidUniqueID; } isInvalid()234 bool isInvalid() const { return SK_InvalidUniqueID == fID; } 235 236 private: UniqueID(uint32_t id)237 explicit UniqueID(uint32_t id) : fID(id) {} 238 239 uint32_t fID; 240 }; 241 242 /* 243 * The contract for the uniqueID is: 244 * for wrapped resources: 245 * the uniqueID will match that of the wrapped resource 246 * 247 * for deferred resources: 248 * the uniqueID will be different from the real resource, when it is allocated 249 * the proxy's uniqueID will not change across the instantiate call 250 * 251 * the uniqueIDs of the proxies and the resources draw from the same pool 252 * 253 * What this boils down to is that the uniqueID of a proxy can be used to consistently 254 * track/identify a proxy but should never be used to distinguish between 255 * resources and proxies - beware! 256 */ uniqueID()257 UniqueID uniqueID() const { return fUniqueID; } 258 underlyingUniqueID()259 UniqueID underlyingUniqueID() const { 260 if (fTarget) { 261 return UniqueID(fTarget->uniqueID()); 262 } 263 264 return fUniqueID; 265 } 266 267 virtual bool instantiate(GrResourceProvider* resourceProvider) = 0; 268 269 /** 270 * Helper that gets the width and height of the surface as a bounding rectangle. 271 */ getBoundsRect()272 SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); } 273 274 /** 275 * @return the texture proxy associated with the surface proxy, may be NULL. 276 */ asTextureProxy()277 virtual GrTextureProxy* asTextureProxy() { return nullptr; } asTextureProxy()278 virtual const GrTextureProxy* asTextureProxy() const { return nullptr; } 279 280 /** 281 * @return the render target proxy associated with the surface proxy, may be NULL. 282 */ asRenderTargetProxy()283 virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; } asRenderTargetProxy()284 virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; } 285 286 /** 287 * Does the resource count against the resource budget? 288 */ isBudgeted()289 SkBudgeted isBudgeted() const { return fBudgeted; } 290 291 void setLastOpList(GrOpList* opList); getLastOpList()292 GrOpList* getLastOpList() { return fLastOpList; } 293 294 GrRenderTargetOpList* getLastRenderTargetOpList(); 295 GrTextureOpList* getLastTextureOpList(); 296 297 /** 298 * Retrieves the amount of GPU memory that will be or currently is used by this resource 299 * in bytes. It is approximate since we aren't aware of additional padding or copies made 300 * by the driver. 301 * 302 * @return the amount of GPU memory used in bytes 303 */ gpuMemorySize()304 size_t gpuMemorySize() const { 305 if (fTarget) { 306 return fTarget->gpuMemorySize(); 307 } 308 if (kInvalidGpuMemorySize == fGpuMemorySize) { 309 fGpuMemorySize = this->onUninstantiatedGpuMemorySize(); 310 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 311 } 312 return fGpuMemorySize; 313 } 314 315 // Helper function that creates a temporary SurfaceContext to perform the copy 316 // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage 317 // to an SkImage. The copy is is not a render target and not multisampled. 318 static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src, 319 SkIRect srcRect, SkBudgeted); 320 321 // Copy the entire 'src' 322 // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial 323 static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src, 324 SkBudgeted budgeted); 325 326 // Test-only entry point - should decrease in use as proxies propagate 327 static sk_sp<GrSurfaceContext> TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, 328 GrSurfaceProxy* srcProxy); 329 330 bool isWrapped_ForTesting() const; 331 332 SkDEBUGCODE(bool isInstantiated() const { return SkToBool(fTarget); }) 333 SkDEBUGCODE(void validate(GrContext*) const;) 334 335 // Provides access to functions that aren't part of the public API. 336 GrSurfaceProxyPriv priv(); 337 const GrSurfaceProxyPriv priv() const; 338 339 protected: 340 // Deferred version GrSurfaceProxy(const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)341 GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags) 342 : fConfig(desc.fConfig) 343 , fWidth(desc.fWidth) 344 , fHeight(desc.fHeight) 345 , fOrigin(desc.fOrigin) 346 , fFit(fit) 347 , fBudgeted(budgeted) 348 , fFlags(flags) 349 , fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) 350 , fGpuMemorySize(kInvalidGpuMemorySize) 351 , fLastOpList(nullptr) { 352 // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources 353 } 354 355 // Wrapped version 356 GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit); 357 358 virtual ~GrSurfaceProxy(); 359 360 friend class GrSurfaceProxyPriv; 361 362 // Methods made available via GrSurfaceProxyPriv hasPendingIO()363 bool hasPendingIO() const { 364 return this->internalHasPendingIO(); 365 } 366 hasPendingWrite()367 bool hasPendingWrite() const { 368 return this->internalHasPendingWrite(); 369 } 370 371 virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0; 372 void assign(sk_sp<GrSurface> surface); 373 374 sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, 375 GrSurfaceFlags flags, bool isMipMapped, 376 SkDestinationSurfaceColorMode mipColorMode) const; 377 378 bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, 379 GrSurfaceFlags flags, bool isMipMapped, 380 SkDestinationSurfaceColorMode mipColorMode); 381 382 // For wrapped resources, 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always be filled in 383 // from the wrapped resource. 384 GrPixelConfig fConfig; 385 int fWidth; 386 int fHeight; 387 GrSurfaceOrigin fOrigin; 388 SkBackingFit fFit; // always exact for wrapped resources 389 mutable SkBudgeted fBudgeted; // set from the backing resource for wrapped resources 390 // mutable bc of SkSurface/SkImage wishy-washiness 391 const uint32_t fFlags; 392 393 const UniqueID fUniqueID; // set from the backing resource for wrapped resources 394 395 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 396 SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) 397 398 private: 399 virtual size_t onUninstantiatedGpuMemorySize() const = 0; 400 401 bool fNeedsClear; 402 403 // This entry is lazily evaluated so, when the proxy wraps a resource, the resource 404 // will be called but, when the proxy is deferred, it will compute the answer itself. 405 // If the proxy computes its own answer that answer is checked (in debug mode) in 406 // the instantiation method. 407 mutable size_t fGpuMemorySize; 408 409 // The last opList that wrote to or is currently going to write to this surface 410 // The opList can be closed (e.g., no surface context is currently bound 411 // to this proxy). 412 // This back-pointer is required so that we can add a dependancy between 413 // the opList used to create the current contents of this surface 414 // and the opList of a destination surface to which this one is being drawn or copied. 415 // This pointer is unreffed. OpLists own a ref on their surface proxies. 416 GrOpList* fLastOpList; 417 418 typedef GrIORefProxy INHERITED; 419 }; 420 421 #endif 422