Remove all knowledge of resource keys from the legacy cache.

BUG=skia:2889

Review URL: https://codereview.chromium.org/705413002
This commit is contained in:
bsalomon 2014-11-11 07:27:16 -08:00 committed by Commit bot
parent a99f9eeed6
commit 6d4488c5e0
7 changed files with 68 additions and 91 deletions

View File

@ -76,6 +76,8 @@ protected:
bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
bool internalHasRef() const { return SkToBool(fRefCnt); }
private: private:
void addPendingRead() const { void addPendingRead() const {
this->validate(); this->validate();
@ -172,16 +174,18 @@ public:
*/ */
virtual size_t gpuMemorySize() const = 0; 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; } GrResourceCacheEntry* getCacheEntry() const { return fCacheEntry; }
bool isScratch() const; bool isScratch() const;
/** /**
* If this resource can be used as a scratch resource this returns a valid * 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. * 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; } const GrResourceKey& getScratchKey() const { return fScratchKey; }
/** /**
* If this resource is currently cached by its contents then this will return * If this resource is currently cached by its contents then this will return
* the content key. Otherwise, NULL is returned. * the content key. Otherwise, NULL is returned.
@ -258,7 +262,11 @@ private:
GrResourceCacheEntry* fCacheEntry; // NULL if not in cache GrResourceCacheEntry* fCacheEntry; // NULL if not in cache
const uint32_t fUniqueID; const uint32_t fUniqueID;
// TODO(bsalomon): Remove GrResourceKey and use different simpler types for content and scratch
// keys.
GrResourceKey fScratchKey; GrResourceKey fScratchKey;
GrResourceKey fContentKey;
bool fContentKeySet;
typedef GrIORef<GrGpuResource> INHERITED; typedef GrIORef<GrGpuResource> INHERITED;
friend class GrIORef<GrGpuResource>; // to access notifyIsPurgable. friend class GrIORef<GrGpuResource>; // to access notifyIsPurgable.

View File

@ -29,7 +29,8 @@ GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
: fGpu(gpu) : fGpu(gpu)
, fCacheEntry(NULL) , fCacheEntry(NULL)
, fUniqueID(CreateUniqueID()) , fUniqueID(CreateUniqueID())
, fScratchKey(GrResourceKey::NullScratchKey()) { , fScratchKey(GrResourceKey::NullScratchKey())
, fContentKeySet(false) {
if (isWrapped) { if (isWrapped) {
fFlags = kWrapped_FlagBit; fFlags = kWrapped_FlagBit;
} else { } else {
@ -78,24 +79,32 @@ GrContext* GrGpuResource::getContext() {
} }
} }
bool GrGpuResource::setCacheEntry(GrResourceCacheEntry* cacheEntry) { bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
// GrResourceCache never changes the cacheEntry once one has been added. SkASSERT(!contentKey.isScratch());
SkASSERT(NULL == cacheEntry || NULL == fCacheEntry); // Currently this can only be called once and can't be called when the resource is scratch.
SkASSERT(this->internalHasRef());
fCacheEntry = cacheEntry; SkASSERT(!this->internalHasPendingIO());
if (this->wasDestroyed() || NULL == cacheEntry) {
return true; if (fContentKeySet) {
return false;
} }
if (!cacheEntry->key().isScratch()) { fContentKey = contentKey;
if (!get_resource_cache2(fGpu)->didAddContentKey(this)) { fContentKeySet = true;
fCacheEntry = NULL;
return false; if (!get_resource_cache2(fGpu)->didSetContentKey(this)) {
} fContentKeySet = false;
return false;
} }
return true; 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 { void GrGpuResource::notifyIsPurgable() const {
if (fCacheEntry && !this->wasDestroyed()) { if (fCacheEntry && !this->wasDestroyed()) {
get_resource_cache(fGpu)->notifyPurgable(this); get_resource_cache(fGpu)->notifyPurgable(this);
@ -110,9 +119,8 @@ void GrGpuResource::setScratchKey(const GrResourceKey& scratchKey) {
} }
const GrResourceKey* GrGpuResource::getContentKey() const { const GrResourceKey* GrGpuResource::getContentKey() const {
// Currently scratch resources have a cache entry in GrResourceCache with a scratch key. if (fContentKeySet) {
if (fCacheEntry && !fCacheEntry->key().isScratch()) { return &fContentKey;
return &fCacheEntry->key();
} }
return NULL; return NULL;
} }

View File

@ -35,14 +35,10 @@ GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpuResource* resource)
const GrResourceKey& key,
GrGpuResource* resource)
: fResourceCache(resourceCache), : fResourceCache(resourceCache),
fKey(key),
fResource(resource), fResource(resource),
fCachedSize(resource->gpuMemorySize()), fCachedSize(resource->gpuMemorySize()) {
fIsExclusive(false) {
// we assume ownership of the resource, and will unref it when we die // we assume ownership of the resource, and will unref it when we die
SkASSERT(resource); SkASSERT(resource);
resource->ref(); resource->ref();
@ -103,9 +99,6 @@ GrResourceCache::~GrResourceCache() {
while (GrResourceCacheEntry* entry = fList.head()) { while (GrResourceCacheEntry* entry = fList.head()) {
GrAutoResourceCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
// remove from our cache
fCache.remove(entry->fKey, entry);
// remove from our llist // remove from our llist
this->internalDetach(entry); this->internalDetach(entry);
@ -155,16 +148,6 @@ void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) {
#endif #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) { void GrResourceCache::makeResourceMRU(GrGpuResource* resource) {
GrResourceCacheEntry* entry = resource->getCacheEntry(); GrResourceCacheEntry* entry = resource->getCacheEntry();
@ -178,11 +161,13 @@ void GrResourceCache::notifyPurgable(const GrGpuResource* resource) {
// Remove scratch textures from the cache the moment they become purgeable if // Remove scratch textures from the cache the moment they become purgeable if
// scratch texture reuse is turned off. // scratch texture reuse is turned off.
SkASSERT(resource->getCacheEntry()); SkASSERT(resource->getCacheEntry());
if (resource->getCacheEntry()->key().getResourceType() == GrTexturePriv::ResourceType() && if (resource->isScratch()) {
resource->getCacheEntry()->key().isScratch() && const GrResourceKey& key = resource->getScratchKey();
!fCaps->reuseScratchTextures() && if (key.getResourceType() == GrTexturePriv::ResourceType() &&
!(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) { !fCaps->reuseScratchTextures() &&
this->deleteResource(resource->getCacheEntry()); !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) {
this->deleteResource(resource->getCacheEntry());
}
} }
} }
@ -190,6 +175,14 @@ bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou
if (NULL != resource->getCacheEntry()) { if (NULL != resource->getCacheEntry()) {
return false; 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 // we don't expect to create new resources during a purge. In theory
// this could cause purgeAsNeeded() into an infinite loop (e.g. // this could cause purgeAsNeeded() into an infinite loop (e.g.
@ -198,15 +191,10 @@ bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou
SkASSERT(!fPurging); SkASSERT(!fPurging);
GrAutoResourceCacheValidate atcv(this); GrAutoResourceCacheValidate atcv(this);
GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, resource)); GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resource));
if (!resource->setCacheEntry(entry)) { resource->setCacheEntry(entry);
SkDELETE(entry);
this->purgeAsNeeded();
return false;
}
this->attachToHead(entry); this->attachToHead(entry);
fCache.insert(key, entry);
this->purgeAsNeeded(); this->purgeAsNeeded();
return true; return true;
} }
@ -244,8 +232,6 @@ void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
fPurging = true; fPurging = true;
this->purgeInvalidated();
this->internalPurge(extraCount, extraBytes); this->internalPurge(extraCount, extraBytes);
if (((fEntryCount+extraCount) > fMaxCount || if (((fEntryCount+extraCount) > fMaxCount ||
(fEntryBytes+extraBytes) > fMaxBytes) && (fEntryBytes+extraBytes) > fMaxBytes) &&
@ -261,22 +247,11 @@ void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
} }
void GrResourceCache::purgeInvalidated() { void GrResourceCache::purgeInvalidated() {
SkTDArray<GrResourceInvalidatedMessage> invalidated; // TODO: Implement this in GrResourceCache2.
fInvalidationInbox.poll(&invalidated);
for (int i = 0; i < invalidated.count(); i++) {
while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor())) {
this->deleteResource(entry);
}
}
} }
void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
SkASSERT(entry->fResource->isPurgable()); SkASSERT(entry->fResource->isPurgable());
// remove from our cache
fCache.remove(entry->key(), entry);
// remove from our llist // remove from our llist
this->internalDetach(entry); this->internalDetach(entry);
delete entry; delete entry;
@ -333,12 +308,6 @@ void GrResourceCache::purgeAllUnlocked() {
fMaxCount = 0; fMaxCount = 0;
this->purgeAsNeeded(); this->purgeAsNeeded();
#ifdef SK_DEBUG
if (!fCache.count()) {
SkASSERT(fList.isEmpty());
}
#endif
fMaxBytes = savedMaxBytes; fMaxBytes = savedMaxBytes;
fMaxCount = savedMaxCount; fMaxCount = savedMaxCount;
} }
@ -367,7 +336,6 @@ static bool both_zero_or_nonzero(int count, size_t bytes) {
void GrResourceCache::validate() const { void GrResourceCache::validate() const {
fList.validate(); fList.validate();
SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
SkASSERT(fEntryCount == fCache.count());
EntryList::Iter iter; EntryList::Iter iter;
@ -378,7 +346,6 @@ void GrResourceCache::validate() const {
int count = 0; int count = 0;
for ( ; entry; entry = iter.next()) { for ( ; entry; entry = iter.next()) {
entry->validate(); entry->validate();
SkASSERT(fCache.find(entry->key()));
count += 1; count += 1;
} }
SkASSERT(count == fEntryCount); SkASSERT(count == fEntryCount);

View File

@ -30,10 +30,10 @@ struct GrResourceInvalidatedMessage {
class GrResourceCacheEntry { class GrResourceCacheEntry {
public: public:
GrGpuResource* resource() const { return fResource; } 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 GrGpuResource* resource) {
static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); } return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource));
}
#ifdef SK_DEBUG #ifdef SK_DEBUG
void validate() const; void validate() const;
#else #else
@ -48,16 +48,12 @@ public:
void didChangeResourceSize(); void didChangeResourceSize();
private: private:
GrResourceCacheEntry(GrResourceCache* resourceCache, GrResourceCacheEntry(GrResourceCache*, GrGpuResource*);
const GrResourceKey& key,
GrGpuResource* resource);
~GrResourceCacheEntry(); ~GrResourceCacheEntry();
GrResourceCache* fResourceCache; GrResourceCache* fResourceCache;
GrResourceKey fKey;
GrGpuResource* fResource; GrGpuResource* fResource;
size_t fCachedSize; size_t fCachedSize;
bool fIsExclusive;
// Linked list for the LRU ordering. // Linked list for the LRU ordering.
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry); SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
@ -205,9 +201,6 @@ private:
static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list); static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
#endif #endif
typedef SkTMultiMap<GrResourceCacheEntry, GrResourceKey> CacheMap;
CacheMap fCache;
// We're an internal doubly linked list // We're an internal doubly linked list
typedef SkTInternalLList<GrResourceCacheEntry> EntryList; typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
EntryList fList; EntryList fList;
@ -232,10 +225,6 @@ private:
void* fOverbudgetData; void* fOverbudgetData;
SkAutoTUnref<const GrDrawTargetCaps> fCaps; 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;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -114,6 +114,7 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey&
return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false))); return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
} }
#if 0
void GrResourceCache2::willRemoveContentKey(const GrGpuResource* resource) { void GrResourceCache2::willRemoveContentKey(const GrGpuResource* resource) {
SkASSERT(resource); SkASSERT(resource);
SkASSERT(resource->getContentKey()); SkASSERT(resource->getContentKey());
@ -122,10 +123,12 @@ void GrResourceCache2::willRemoveContentKey(const GrGpuResource* resource) {
fContentHash.remove(*resource->getContentKey()); fContentHash.remove(*resource->getContentKey());
} }
#endif
bool GrResourceCache2::didAddContentKey(GrGpuResource* resource) { bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
SkASSERT(resource); SkASSERT(resource);
SkASSERT(resource->getContentKey()); SkASSERT(resource->getContentKey());
SkASSERT(!resource->getContentKey()->isScratch());
GrGpuResource* res = fContentHash.find(*resource->getContentKey()); GrGpuResource* res = fContentHash.find(*resource->getContentKey());
if (NULL != res) { if (NULL != res) {

View File

@ -29,13 +29,11 @@ public:
void removeResource(GrGpuResource*); void removeResource(GrGpuResource*);
void willRemoveContentKey(const GrGpuResource*);
// This currently returns a bool and fails when an existing resource has a key that collides // 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 // 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 // resource. The failure is a temporary measure taken because duties are split between two
// cache objects currently. // cache objects currently.
bool didAddContentKey(GrGpuResource*); bool didSetContentKey(GrGpuResource*);
void abandonAll(); void abandonAll();

View File

@ -271,17 +271,21 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
const GrResourceInvalidatedMessage msg2 = { key2 }; const GrResourceInvalidatedMessage msg2 = { key2 };
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2); SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
cache->purgeAsNeeded(); cache->purgeAsNeeded();
#if 0 // Disabled until reimplemented in GrResourceCache2.
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1)); REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2)); REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
REPORTER_ASSERT(reporter, cache2->hasContentKey(key3)); REPORTER_ASSERT(reporter, cache2->hasContentKey(key3));
#endif
// Invalidate the third. // Invalidate the third.
const GrResourceInvalidatedMessage msg3 = { key3 }; const GrResourceInvalidatedMessage msg3 = { key3 };
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3); SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
cache->purgeAsNeeded(); cache->purgeAsNeeded();
#if 0 // Disabled until reimplemented in GrResourceCache2.
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3)); REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
#endif
} }
static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) { static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {