diff options
author | 2014-09-03 14:05:49 -0700 | |
---|---|---|
committer | 2014-09-03 14:05:49 -0700 | |
commit | 00b76bd750e668a6989dd497313e715d1b476fdc (patch) | |
tree | 62342a335023875d1482447bea9e29e8a0ba22fb | |
parent | ab799fe66c69e70b05c88791350c59c015e214ff (diff) |
Add reference base class to GrGpuResourcewith pending IO references.
BUG=skia:2889
R=robertphillips@google.com
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/533343002
-rw-r--r-- | include/gpu/GrGpuResource.h | 108 | ||||
-rw-r--r-- | src/gpu/GrGpuResource.cpp | 12 |
2 files changed, 105 insertions, 15 deletions
diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h index 5e852a9a04..f18f5c5050 100644 --- a/include/gpu/GrGpuResource.h +++ b/include/gpu/GrGpuResource.h @@ -18,25 +18,108 @@ class GrGpu; class GrContext; /** - * Base class for objects that can be kept in the GrResourceCache. + * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base + * class to isolate the ref-cnting behavior and provide friendship without exposing all of + * GrGpuResource. + * + * Gpu resources can have three types of refs: + * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls + * that read and write the resource via GrDrawTarget and by any object that must own a + * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code. + * 2) Pending read (+ by addPendingRead(), - by readCompleted()): GrContext has scheduled a read + * of the resource by the GPU as a result of a skia API call but hasn't executed it yet. + * 3) Pending write (+ by addPendingWrite(), - by writeCompleted()): GrContext has scheduled a + * write to the resource by the GPU as a result of a skia API call but hasn't executed it yet. + * + * The latter two ref types are private and intended only for Gr core code. */ -class GrGpuResource : public SkNoncopyable { +class GrGpuRef : public SkNoncopyable { public: - SK_DECLARE_INST_COUNT_ROOT(GrGpuResource) + SK_DECLARE_INST_COUNT_ROOT(GrGpuRef) + + virtual ~GrGpuRef(); - // These method signatures are written to mirror SkRefCnt. However, we don't require - // thread safety as GrCacheable objects are not intended to cross thread boundaries. + // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with + // templated helper classes (e.g. SkAutoTUnref). However, we have different categories of + // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are + // not intended to cross thread boundaries. // internal_dispose() exists because of GrTexture's reliance on it. It will be removed // soon. - void ref() const { ++fRefCnt; } - void unref() const { --fRefCnt; if (0 == fRefCnt) { this->internal_dispose(); } } + void ref() const { + ++fRefCnt; + // pre-validate once internal_dispose is removed (and therefore 0 ref cnt is not allowed). + this->validate(); + } + + void unref() const { + this->validate(); + --fRefCnt; + if (0 == fRefCnt && 0 == fPendingReads && 0 == fPendingWrites) { + this->internal_dispose(); + } + } + virtual void internal_dispose() const { SkDELETE(this); } - bool unique() const { return 1 == fRefCnt; } -#ifdef SK_DEBUG + + /** This is exists to service the old mechanism for recycling scratch textures. It will + be removed soon. */ + bool unique() const { return 1 == (fRefCnt + fPendingReads + fPendingWrites); } + void validate() const { - SkASSERT(fRefCnt > 0); - } +#ifdef SK_DEBUG + SkASSERT(fRefCnt >= 0); + SkASSERT(fPendingReads >= 0); + SkASSERT(fPendingWrites >= 0); + SkASSERT(fRefCnt + fPendingReads + fPendingWrites > 0); #endif + } + +protected: + GrGpuRef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {} + +private: + void addPendingRead() const { + this->validate(); + ++fPendingReads; + } + + void completedRead() const { + this->validate(); + --fPendingReads; + if (0 == fRefCnt && 0 == fPendingReads && 0 == fPendingWrites) { + this->internal_dispose(); + } + } + + void addPendingWrite() const { + this->validate(); + ++fPendingWrites; + } + + void completedWrite() const { + this->validate(); + --fPendingWrites; + if (0 == fRefCnt && 0 == fPendingReads && 0 == fPendingWrites) { + this->internal_dispose(); + } + } + +private: + mutable int32_t fRefCnt; + mutable int32_t fPendingReads; + mutable int32_t fPendingWrites; + + // These functions need access to the pending read/write member functions. + friend class GrDrawState; + friend class GrProgramResource; +}; + +/** + * Base class for objects that can be kept in the GrResourceCache. + */ +class GrGpuResource : public GrGpuRef { +public: + SK_DECLARE_INST_COUNT(GrGpuResource) /** * Frees the object in the underlying 3D API. It must be safe to call this @@ -154,13 +237,12 @@ private: uint32_t fFlags; - mutable int32_t fRefCnt; GrResourceCacheEntry* fCacheEntry; // NULL if not in cache const uint32_t fUniqueID; GrResourceKey fScratchKey; - typedef SkNoncopyable INHERITED; + typedef GrGpuRef INHERITED; }; #endif diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp index bce7d2cae8..d29ab6d486 100644 --- a/src/gpu/GrGpuResource.cpp +++ b/src/gpu/GrGpuResource.cpp @@ -11,6 +11,16 @@ #include "GrResourceCache2.h" #include "GrGpu.h" +GrGpuRef::~GrGpuRef() { + SkASSERT(0 == fRefCnt); + SkASSERT(0 == fPendingReads); + SkASSERT(0 == fPendingWrites); + // Set to invalid values. + SkDEBUGCODE(fRefCnt = fPendingReads = fPendingWrites = -10;) +} + +/////////////////////////////////////////////////////////////////////////////// + static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) { SkASSERT(NULL != gpu); SkASSERT(NULL != gpu->getContext()); @@ -20,7 +30,6 @@ static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) { GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped) : fGpu(gpu) - , fRefCnt(1) , fCacheEntry(NULL) , fUniqueID(CreateUniqueID()) , fScratchKey(GrResourceKey::NullScratchKey()) { @@ -36,7 +45,6 @@ void GrGpuResource::registerWithCache() { } GrGpuResource::~GrGpuResource() { - SkASSERT(0 == fRefCnt); // subclass should have released this. SkASSERT(this->wasDestroyed()); } |