aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Robert Phillips <robertphillips@google.com>2018-03-28 12:25:42 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-28 18:56:14 +0000
commit6eba063b63efbf824aff8ec6b32af05e4d54c38b (patch)
treeb3b5ef8a90cd5757ae0fe40caf3471ae6289a96e
parentaa5da735fa27cdb60f55f94bbd2149727c9c0728 (diff)
Add new GrResourceCache::purgeUnlockedResources variant
TBR=bsalomon@google.com Change-Id: I05bef1f8a271474db878a046cc1f6ac7b60a15f1 Reviewed-on: https://skia-review.googlesource.com/116801 Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
-rw-r--r--include/gpu/GrContext.h15
-rw-r--r--src/gpu/GrContext.cpp7
-rw-r--r--src/gpu/GrResourceCache.cpp35
-rw-r--r--src/gpu/GrResourceCache.h7
-rw-r--r--tests/ResourceCacheTest.cpp69
5 files changed, 125 insertions, 8 deletions
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 8200dd4da8..6903dc3af0 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -188,6 +188,21 @@ public:
*/
void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources);
+ /**
+ * This entry point is intended for instances where an app has been backgrounded or
+ * suspended.
+ * If 'scratchResourcesOnly' is true all unlocked scratch resources will be purged but the
+ * unlocked resources with persistent data will remain. If 'scratchResourcesOnly' is false
+ * then all unlocked resources will be purged.
+ * In either case, after the unlocked resources are purged a separate pass will be made to
+ * ensure that resource usage is under budget (i.e., even if 'scratchResourcesOnly' is true
+ * some resources with persistent data may be purged to be under budget).
+ *
+ * @param scratchResourcesOnly If true only unlocked scratch resources will be purged prior
+ * enforcing the budget requirements.
+ */
+ void purgeUnlockedResources(bool scratchResourcesOnly);
+
/** Access the context capabilities */
const GrCaps* caps() const { return fCaps.get(); }
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 3baf0b9737..db13931b2b 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -254,6 +254,13 @@ void GrContext::freeGpuResources() {
fResourceCache->purgeAllUnlocked();
}
+void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) {
+ ASSERT_SINGLE_OWNER
+ fResourceCache->purgeUnlockedResources(scratchResourcesOnly);
+ fResourceCache->purgeAsNeeded();
+ fTextBlobCache->purgeStaleBlobs();
+}
+
void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
ASSERT_SINGLE_OWNER
fResourceCache->purgeAsNeeded();
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 50b2e9a229..d2eb91c0e8 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -513,13 +513,34 @@ void GrResourceCache::purgeAsNeeded() {
}
}
-void GrResourceCache::purgeAllUnlocked() {
- // We could disable maintaining the heap property here, but it would add a lot of complexity.
- // Moreover, this is rarely called.
- while (fPurgeableQueue.count()) {
- GrGpuResource* resource = fPurgeableQueue.peek();
- SkASSERT(resource->isPurgeable());
- resource->cacheAccess().release();
+void GrResourceCache::purgeUnlockedResources(bool scratchResourcesOnly) {
+ if (!scratchResourcesOnly) {
+ // We could disable maintaining the heap property here, but it would add a lot of
+ // complexity. Moreover, this is rarely called.
+ while (fPurgeableQueue.count()) {
+ GrGpuResource* resource = fPurgeableQueue.peek();
+ SkASSERT(resource->isPurgeable());
+ resource->cacheAccess().release();
+ }
+ } else {
+ // Sort the queue
+ fPurgeableQueue.sort();
+
+ // Make a list of the scratch resources to delete
+ SkTDArray<GrGpuResource*> scratchResources;
+ for (int i = 0; i < fPurgeableQueue.count(); i++) {
+ GrGpuResource* resource = fPurgeableQueue.at(i);
+ SkASSERT(resource->isPurgeable());
+ if (!resource->getUniqueKey().isValid()) {
+ *scratchResources.append() = resource;
+ }
+ }
+
+ // Delete the scratch resources. This must be done as a separate pass
+ // to avoid messing up the sorted order of the queue
+ for (int i = 0; i < scratchResources.count(); i++) {
+ scratchResources.getAt(i)->cacheAccess().release();
+ }
}
this->validate();
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index 07f04a82eb..b91e664d18 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -168,7 +168,12 @@ public:
void purgeAsNeeded();
/** Purges all resources that don't have external owners. */
- void purgeAllUnlocked();
+ void purgeAllUnlocked() { this->purgeUnlockedResources(false); }
+
+ // Purge unlocked resources. If 'scratchResourcesOnly' is true the purgeable resources
+ // containing persistent data are spared. If it is false then all purgeable resources will
+ // be deleted.
+ void purgeUnlockedResources(bool scratchResourcesOnly);
/** Purge all resources not used since the passed in time. */
void purgeResourcesNotUsedSince(GrStdSteadyClock::time_point);
diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp
index 7b0abc1d2a..c56bd01564 100644
--- a/tests/ResourceCacheTest.cpp
+++ b/tests/ResourceCacheTest.cpp
@@ -427,6 +427,74 @@ static void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullpt
builder[0] = data;
}
+static void test_purge_unlocked(skiatest::Reporter* reporter) {
+ Mock mock(10, 30000);
+ GrContext* context = mock.context();
+ GrResourceCache* cache = mock.cache();
+ GrGpu* gpu = context->contextPriv().getGpu();
+
+ // Create two resource w/ a unique key and two w/o but all of which have scratch keys.
+ TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
+ TestResource::kA_SimulatedProperty);
+ a->setSize(11);
+
+ GrUniqueKey uniqueKey;
+ make_unique_key<0>(&uniqueKey, 0);
+
+ TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
+ TestResource::kA_SimulatedProperty);
+ b->setSize(12);
+ b->resourcePriv().setUniqueKey(uniqueKey);
+
+ TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
+ TestResource::kA_SimulatedProperty);
+ c->setSize(13);
+
+ GrUniqueKey uniqueKey2;
+ make_unique_key<0>(&uniqueKey2, 1);
+
+ TestResource* d = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
+ TestResource::kA_SimulatedProperty);
+ d->setSize(14);
+ d->resourcePriv().setUniqueKey(uniqueKey2);
+
+
+ REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
+ REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
+ d->gpuMemorySize() == cache->getResourceBytes());
+
+ // Should be safe to purge without deleting the resources since we still have refs.
+ cache->purgeUnlockedResources(false);
+ REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
+
+ // Unref them all. Since they all have keys they should remain in the cache.
+
+ a->unref();
+ b->unref();
+ c->unref();
+ d->unref();
+ REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
+ REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
+ d->gpuMemorySize() == cache->getResourceBytes());
+
+ // Purge only the two scratch resources
+ cache->purgeUnlockedResources(true);
+
+ REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
+ REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
+ cache->getResourceBytes());
+
+ // Purge the uniquely keyed resources
+ cache->purgeUnlockedResources(false);
+
+ REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
+ REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
+}
+
static void test_budgeting(skiatest::Reporter* reporter) {
Mock mock(10, 300);
GrContext* context = mock.context();
@@ -1622,6 +1690,7 @@ static void test_tags(skiatest::Reporter* reporter) {
DEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) {
// The below tests create their own mock contexts.
test_no_key(reporter);
+ test_purge_unlocked(reporter);
test_budgeting(reporter);
test_unbudgeted(reporter);
test_unbudgeted_to_scratch(reporter);