Add GrResourceCache::purgeToMakeHeadroom

This function will be used by the resource allocator to figure out
whether an allocation plan is feasible without committing to it.

Bug: skia:10877
Change-Id: I135b7b80d53d9c3541d2fa0313d91d14a1d54eb2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/394156
Commit-Queue: Adlai Holler <adlai@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Auto-Submit: Adlai Holler <adlai@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Adlai Holler 2021-04-08 15:30:12 -04:00 committed by Skia Commit-Bot
parent 022636b15a
commit e1c8a38794
4 changed files with 75 additions and 1 deletions

View File

@ -124,7 +124,7 @@ public:
/**
* Retrieves the context that owns the object. Note that it is possible for
* this to return NULL. When objects have been release()ed or abandon()ed
* they no longer have an owning context. Destroying a GrContext
* they no longer have an owning context. Destroying a GrDirectContext
* automatically releases all its resources.
*/
const GrDirectContext* getContext() const;

View File

@ -7,6 +7,7 @@
#include "src/gpu/GrResourceCache.h"
#include <atomic>
#include <vector>
#include "include/gpu/GrDirectContext.h"
#include "include/private/GrSingleOwner.h"
#include "include/private/SkTo.h"
@ -619,6 +620,40 @@ void GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point pu
}
}
bool GrResourceCache::purgeToMakeHeadroom(size_t desiredHeadroomBytes) {
AutoValidate av(this);
if (this->wouldFit(desiredHeadroomBytes)) {
return true;
}
fPurgeableQueue.sort();
size_t headroom = this->overBudget() ? 0 : fMaxBytes - fBudgetedBytes;
int purgeCnt = 0;
for (int i = 0; i < fPurgeableQueue.count(); i++) {
GrGpuResource* resource = fPurgeableQueue.at(i);
headroom += resource->gpuMemorySize();
if (headroom >= desiredHeadroomBytes) {
purgeCnt = i + 1;
break;
}
}
if (headroom < desiredHeadroomBytes) {
return false;
}
// Success! Release the resources.
// Copy to array first so we don't mess with the queue.
std::vector<GrGpuResource*> resources;
resources.reserve(purgeCnt);
for (int i = 0; i < purgeCnt; i++) {
resources.push_back(fPurgeableQueue.at(i));
}
for (GrGpuResource* resource : resources) {
resource->cacheAccess().release();
}
return true;
}
void GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
const size_t tmpByteBudget = std::max((size_t)0, fBytes - bytesToPurge);

View File

@ -165,6 +165,11 @@ public:
/** Purge all resources not used since the passed in time. */
void purgeResourcesNotUsedSince(GrStdSteadyClock::time_point);
/** If it's possible to purge enough resources to get the provided amount of budget
headroom, do so and return true. If it's not possible, do nothing and return false.
*/
bool purgeToMakeHeadroom(size_t desiredHeadroomBytes);
bool overBudget() const { return fBudgetedBytes > fMaxBytes; }
/**

View File

@ -1733,6 +1733,40 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GPUMemorySize, reporter, ctxInfo) {
}
}
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PurgeToMakeHeadroom, reporter, ctxInfo) {
constexpr size_t kTexSize = 16 * 16 * 4;
auto dContext = ctxInfo.directContext();
dContext->setResourceCacheLimit(2 * kTexSize);
auto resourceProvider = dContext->priv().resourceProvider();
auto resourceCache = dContext->priv().getResourceCache();
for (bool success : { true, false }) {
reporter->push(SkString(success ? "success" : "failure"));
resourceCache->releaseAll();
REPORTER_ASSERT(reporter, resourceCache->getBudgetedResourceBytes() == 0);
// Make one unpurgeable texture and one purgeable texture.
auto lockedTex = make_normal_texture(resourceProvider, GrRenderable::kNo, {16, 16}, 1);
REPORTER_ASSERT(reporter, lockedTex->gpuMemorySize() == kTexSize);
// N.b. this surface is renderable so "reuseScratchTextures = false" won't mess us up.
auto purgeableTex = make_normal_texture(resourceProvider, GrRenderable::kYes, {16, 16}, 1);
if (success) {
purgeableTex = nullptr;
}
size_t expectedPurgeable = success ? kTexSize : 0;
REPORTER_ASSERT(reporter, expectedPurgeable == resourceCache->getPurgeableBytes(),
"%zu vs %zu", expectedPurgeable, resourceCache->getPurgeableBytes());
REPORTER_ASSERT(reporter, success == resourceCache->purgeToMakeHeadroom(kTexSize));
size_t expectedBudgeted = success ? kTexSize : (2 * kTexSize);
REPORTER_ASSERT(reporter, expectedBudgeted == resourceCache->getBudgetedResourceBytes(),
"%zu vs %zu", expectedBudgeted, resourceCache->getBudgetedResourceBytes());
reporter->pop();
}
}
#if GR_GPU_STATS
DEF_GPUTEST_FOR_MOCK_CONTEXT(OverbudgetFlush, reporter, ctxInfo) {
auto context = ctxInfo.directContext();