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