#include "SkInstCnt.h"
#include "SkTInternalLList.h"
+#include "GrResourceKey.h"
class GrResourceCacheEntry;
+class GrResourceCache2;
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 GrIORef : public SkNoncopyable {
public:
- SK_DECLARE_INST_COUNT_ROOT(GrGpuResource)
+ SK_DECLARE_INST_COUNT_ROOT(GrIORef)
+
+ enum IOType {
+ kRead_IOType,
+ kWrite_IOType,
+ kRW_IOType
+ };
+
+ virtual ~GrIORef();
- // 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:
+ GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {}
+
+ bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
+ bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
+ bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
+
+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;
+
+ // This class is used to manage conversion of refs to pending reads/writes.
+ friend class GrGpuResourceRef;
+ template <typename, IOType> friend class GrPendingIOResource;
+};
+
+/**
+ * Base class for objects that can be kept in the GrResourceCache.
+ */
+class GrGpuResource : public GrIORef {
+public:
+ SK_DECLARE_INST_COUNT(GrGpuResource)
/**
* Frees the object in the underlying 3D API. It must be safe to call this
void setCacheEntry(GrResourceCacheEntry* cacheEntry) { fCacheEntry = cacheEntry; }
GrResourceCacheEntry* getCacheEntry() { return fCacheEntry; }
+ /**
+ * If this resource can be used as a scratch resource this returns a valid
+ * scratch key. Otherwise it returns a key for which isNullScratch is true.
+ */
+ const GrResourceKey& getScratchKey() const { return fScratchKey; }
+
/**
- * Gets an id that is unique for this GrCacheable object. It is static in that it does
- * not change when the content of the GrCacheable object changes. This will never return
+ * Gets an id that is unique for this GrGpuResource object. It is static in that it does
+ * not change when the content of the GrGpuResource object changes. This will never return
* 0.
*/
uint32_t getUniqueID() const { return fUniqueID; }
protected:
+ // This must be called by every GrGpuObject. It should be called once the object is fully
+ // initialized (i.e. not in a base class constructor).
+ void registerWithCache();
+
GrGpuResource(GrGpu*, bool isWrapped);
virtual ~GrGpuResource();
- bool isInCache() const { return NULL != fCacheEntry; }
+ bool isInCache() const { return SkToBool(fCacheEntry); }
GrGpu* getGpu() const { return fGpu; }
*/
void didChangeGpuMemorySize() const;
+ /**
+ * Optionally called by the GrGpuResource subclass if the resource can be used as scratch.
+ * By default resources are not usable as scratch. This should only be called once.
+ **/
+ void setScratchKey(const GrResourceKey& scratchKey);
+
private:
#ifdef SK_DEBUG
friend class GrGpu; // for assert in GrGpu to access getGpu
static uint32_t CreateUniqueID();
- // We're in an internal doubly linked list
+ // We're in an internal doubly linked list owned by GrResourceCache2
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrGpuResource);
- GrGpu* fGpu; // not reffed. The GrGpu can be deleted while there
- // are still live GrGpuResources. It will call
- // release() on all such objects in its destructor.
+ // This is not ref'ed but abandon() or release() will be called before the GrGpu object
+ // is destroyed. Those calls set will this to NULL.
+ GrGpu* fGpu;
+
enum Flags {
/**
* This object wraps a GPU object given to us by the user.
uint32_t fFlags;
- mutable int32_t fRefCnt;
GrResourceCacheEntry* fCacheEntry; // NULL if not in cache
const uint32_t fUniqueID;
- typedef SkNoncopyable INHERITED;
+ GrResourceKey fScratchKey;
+
+ typedef GrIORef INHERITED;
};
#endif