bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
+ bool internalHasRef() const { return SkToBool(fRefCnt); }
+
private:
void addPendingRead() const {
this->validate();
*/
virtual size_t gpuMemorySize() const = 0;
- bool setCacheEntry(GrResourceCacheEntry* cacheEntry);
+ // TODO(bsalomon): Move this stuff to GrGpuResourcePriv.
+ bool setContentKey(const GrResourceKey& contentKey);
+ void setCacheEntry(GrResourceCacheEntry* cacheEntry);
GrResourceCacheEntry* getCacheEntry() const { return fCacheEntry; }
bool isScratch() const;
-
/**
* 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.
+ * The resource may currently be used as content resource rather than scratch.
+ * Check isScratch().
*/
const GrResourceKey& getScratchKey() const { return fScratchKey; }
-
/**
* If this resource is currently cached by its contents then this will return
* the content key. Otherwise, NULL is returned.
GrResourceCacheEntry* fCacheEntry; // NULL if not in cache
const uint32_t fUniqueID;
+ // TODO(bsalomon): Remove GrResourceKey and use different simpler types for content and scratch
+ // keys.
GrResourceKey fScratchKey;
+ GrResourceKey fContentKey;
+ bool fContentKeySet;
typedef GrIORef<GrGpuResource> INHERITED;
friend class GrIORef<GrGpuResource>; // to access notifyIsPurgable.
: fGpu(gpu)
, fCacheEntry(NULL)
, fUniqueID(CreateUniqueID())
- , fScratchKey(GrResourceKey::NullScratchKey()) {
+ , fScratchKey(GrResourceKey::NullScratchKey())
+ , fContentKeySet(false) {
if (isWrapped) {
fFlags = kWrapped_FlagBit;
} else {
}
}
-bool GrGpuResource::setCacheEntry(GrResourceCacheEntry* cacheEntry) {
- // GrResourceCache never changes the cacheEntry once one has been added.
- SkASSERT(NULL == cacheEntry || NULL == fCacheEntry);
-
- fCacheEntry = cacheEntry;
- if (this->wasDestroyed() || NULL == cacheEntry) {
- return true;
+bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
+ SkASSERT(!contentKey.isScratch());
+ // Currently this can only be called once and can't be called when the resource is scratch.
+ SkASSERT(this->internalHasRef());
+ SkASSERT(!this->internalHasPendingIO());
+
+ if (fContentKeySet) {
+ return false;
}
- if (!cacheEntry->key().isScratch()) {
- if (!get_resource_cache2(fGpu)->didAddContentKey(this)) {
- fCacheEntry = NULL;
- return false;
- }
+ fContentKey = contentKey;
+ fContentKeySet = true;
+
+ if (!get_resource_cache2(fGpu)->didSetContentKey(this)) {
+ fContentKeySet = false;
+ return false;
}
return true;
}
+void GrGpuResource::setCacheEntry(GrResourceCacheEntry* cacheEntry) {
+ // GrResourceCache never changes the cacheEntry once one has been added.
+ SkASSERT(NULL == cacheEntry || NULL == fCacheEntry);
+ fCacheEntry = cacheEntry;
+}
+
void GrGpuResource::notifyIsPurgable() const {
if (fCacheEntry && !this->wasDestroyed()) {
get_resource_cache(fGpu)->notifyPurgable(this);
}
const GrResourceKey* GrGpuResource::getContentKey() const {
- // Currently scratch resources have a cache entry in GrResourceCache with a scratch key.
- if (fCacheEntry && !fCacheEntry->key().isScratch()) {
- return &fCacheEntry->key();
+ if (fContentKeySet) {
+ return &fContentKey;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
-GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache,
- const GrResourceKey& key,
- GrGpuResource* resource)
+GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpuResource* resource)
: fResourceCache(resourceCache),
- fKey(key),
fResource(resource),
- fCachedSize(resource->gpuMemorySize()),
- fIsExclusive(false) {
+ fCachedSize(resource->gpuMemorySize()) {
// we assume ownership of the resource, and will unref it when we die
SkASSERT(resource);
resource->ref();
while (GrResourceCacheEntry* entry = fList.head()) {
GrAutoResourceCacheValidate atcv(this);
- // remove from our cache
- fCache.remove(entry->fKey, entry);
-
// remove from our llist
this->internalDetach(entry);
#endif
}
-// This functor just searches for an entry with only a single ref (from
-// the texture cache itself). Presumably in this situation no one else
-// is relying on the texture.
-class GrTFindUnreffedFunctor {
-public:
- bool operator()(const GrResourceCacheEntry* entry) const {
- return entry->resource()->isPurgable();
- }
-};
-
void GrResourceCache::makeResourceMRU(GrGpuResource* resource) {
GrResourceCacheEntry* entry = resource->getCacheEntry();
// Remove scratch textures from the cache the moment they become purgeable if
// scratch texture reuse is turned off.
SkASSERT(resource->getCacheEntry());
- if (resource->getCacheEntry()->key().getResourceType() == GrTexturePriv::ResourceType() &&
- resource->getCacheEntry()->key().isScratch() &&
- !fCaps->reuseScratchTextures() &&
- !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) {
- this->deleteResource(resource->getCacheEntry());
+ if (resource->isScratch()) {
+ const GrResourceKey& key = resource->getScratchKey();
+ if (key.getResourceType() == GrTexturePriv::ResourceType() &&
+ !fCaps->reuseScratchTextures() &&
+ !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) {
+ this->deleteResource(resource->getCacheEntry());
+ }
}
}
if (NULL != resource->getCacheEntry()) {
return false;
}
+
+ if (key.isScratch()) {
+ SkASSERT(resource->isScratch() && key == resource->getScratchKey());
+ } else {
+ if (!resource->setContentKey(key)) {
+ return false;
+ }
+ }
// we don't expect to create new resources during a purge. In theory
// this could cause purgeAsNeeded() into an infinite loop (e.g.
SkASSERT(!fPurging);
GrAutoResourceCacheValidate atcv(this);
- GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, resource));
- if (!resource->setCacheEntry(entry)) {
- SkDELETE(entry);
- this->purgeAsNeeded();
- return false;
- }
+ GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resource));
+ resource->setCacheEntry(entry);
this->attachToHead(entry);
- fCache.insert(key, entry);
this->purgeAsNeeded();
return true;
}
fPurging = true;
- this->purgeInvalidated();
-
this->internalPurge(extraCount, extraBytes);
if (((fEntryCount+extraCount) > fMaxCount ||
(fEntryBytes+extraBytes) > fMaxBytes) &&
}
void GrResourceCache::purgeInvalidated() {
- SkTDArray<GrResourceInvalidatedMessage> invalidated;
- fInvalidationInbox.poll(&invalidated);
-
- for (int i = 0; i < invalidated.count(); i++) {
- while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor())) {
- this->deleteResource(entry);
- }
- }
+ // TODO: Implement this in GrResourceCache2.
}
void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
SkASSERT(entry->fResource->isPurgable());
-
- // remove from our cache
- fCache.remove(entry->key(), entry);
-
// remove from our llist
this->internalDetach(entry);
delete entry;
fMaxCount = 0;
this->purgeAsNeeded();
-#ifdef SK_DEBUG
- if (!fCache.count()) {
- SkASSERT(fList.isEmpty());
- }
-#endif
-
fMaxBytes = savedMaxBytes;
fMaxCount = savedMaxCount;
}
void GrResourceCache::validate() const {
fList.validate();
SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
- SkASSERT(fEntryCount == fCache.count());
EntryList::Iter iter;
int count = 0;
for ( ; entry; entry = iter.next()) {
entry->validate();
- SkASSERT(fCache.find(entry->key()));
count += 1;
}
SkASSERT(count == fEntryCount);
class GrResourceCacheEntry {
public:
GrGpuResource* resource() const { return fResource; }
- const GrResourceKey& key() const { return fKey; }
- static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
- static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
+ static uint32_t Hash(const GrGpuResource* resource) {
+ return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource));
+ }
#ifdef SK_DEBUG
void validate() const;
#else
void didChangeResourceSize();
private:
- GrResourceCacheEntry(GrResourceCache* resourceCache,
- const GrResourceKey& key,
- GrGpuResource* resource);
+ GrResourceCacheEntry(GrResourceCache*, GrGpuResource*);
~GrResourceCacheEntry();
GrResourceCache* fResourceCache;
- GrResourceKey fKey;
GrGpuResource* fResource;
size_t fCachedSize;
- bool fIsExclusive;
// Linked list for the LRU ordering.
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
#endif
- typedef SkTMultiMap<GrResourceCacheEntry, GrResourceKey> CacheMap;
- CacheMap fCache;
-
// We're an internal doubly linked list
typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
EntryList fList;
void* fOverbudgetData;
SkAutoTUnref<const GrDrawTargetCaps> fCaps;
-
- // Listen for messages that a resource has been invalidated and purge cached junk proactively.
- typedef SkMessageBus<GrResourceInvalidatedMessage>::Inbox Inbox;
- Inbox fInvalidationInbox;
};
///////////////////////////////////////////////////////////////////////////////
return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
}
+#if 0
void GrResourceCache2::willRemoveContentKey(const GrGpuResource* resource) {
SkASSERT(resource);
SkASSERT(resource->getContentKey());
fContentHash.remove(*resource->getContentKey());
}
+#endif
-bool GrResourceCache2::didAddContentKey(GrGpuResource* resource) {
+bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
SkASSERT(resource);
SkASSERT(resource->getContentKey());
+ SkASSERT(!resource->getContentKey()->isScratch());
GrGpuResource* res = fContentHash.find(*resource->getContentKey());
if (NULL != res) {
void removeResource(GrGpuResource*);
- void willRemoveContentKey(const GrGpuResource*);
-
// This currently returns a bool and fails when an existing resource has a key that collides
// with the new content key. In the future it will null out the content key for the existing
// resource. The failure is a temporary measure taken because duties are split between two
// cache objects currently.
- bool didAddContentKey(GrGpuResource*);
+ bool didSetContentKey(GrGpuResource*);
void abandonAll();
const GrResourceInvalidatedMessage msg2 = { key2 };
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
cache->purgeAsNeeded();
+#if 0 // Disabled until reimplemented in GrResourceCache2.
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
REPORTER_ASSERT(reporter, cache2->hasContentKey(key3));
+#endif
// Invalidate the third.
const GrResourceInvalidatedMessage msg3 = { key3 };
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
cache->purgeAsNeeded();
+#if 0 // Disabled until reimplemented in GrResourceCache2.
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
+#endif
}
static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {