Add GrResourceAllocator::makeBudgetHeadroom
This allows the caller to decide whether a plan is feasible before
committing to it. In this CL the drawing manager doesn't actually
call it, but we test it. We'll call it in a follow-up CL
Bug: skia:10877
Change-Id: Ie3a6c14a0196f595c522a0c961aba7b10c980711
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/394157
Commit-Queue: Adlai Holler <adlai@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 9f983f6..e1ce658 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -211,6 +211,7 @@
task->gatherProxyIntervals(&alloc);
}
+ // TODO: Call makeBudgetHeadroom before proceeding with reordered DAG.
flushed = alloc.planAssignment() && alloc.assign() && this->executeRenderTasks(&flushState);
}
this->removeRenderTasks();
diff --git a/src/gpu/GrResourceAllocator.cpp b/src/gpu/GrResourceAllocator.cpp
index 9fc6afe..1dff77d 100644
--- a/src/gpu/GrResourceAllocator.cpp
+++ b/src/gpu/GrResourceAllocator.cpp
@@ -362,6 +362,31 @@
return !fFailedInstantiation;
}
+bool GrResourceAllocator::makeBudgetHeadroom() {
+ SkASSERT(fPlanned);
+ SkASSERT(!fFailedInstantiation);
+ size_t additionalBytesNeeded = 0;
+ for (Interval* cur = fFinishedIntvls.peekHead(); cur; cur = cur->next()) {
+ GrSurfaceProxy* proxy = cur->proxy();
+ if (SkBudgeted::kNo == proxy->isBudgeted() || proxy->isInstantiated()) {
+ continue;
+ }
+
+ // N.B Fully-lazy proxies were already instantiated in planAssignment
+ if (proxy->isLazy()) {
+ additionalBytesNeeded += proxy->gpuMemorySize();
+ } else {
+ Register* r = cur->getRegister();
+ SkASSERT(r);
+ if (!r->accountedForInBudget() && !r->existingSurface()) {
+ additionalBytesNeeded += proxy->gpuMemorySize();
+ }
+ r->setAccountedForInBudget();
+ }
+ }
+ return fDContext->priv().getResourceCache()->purgeToMakeHeadroom(additionalBytesNeeded);
+}
+
bool GrResourceAllocator::assign() {
SkASSERT(fPlanned && !fAssigned);
SkDEBUGCODE(fAssigned = true;)
diff --git a/src/gpu/GrResourceAllocator.h b/src/gpu/GrResourceAllocator.h
index 301a26b..8175dca 100644
--- a/src/gpu/GrResourceAllocator.h
+++ b/src/gpu/GrResourceAllocator.h
@@ -91,11 +91,16 @@
void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end, ActualUse actualUse
SkDEBUGCODE(, bool isDirectDstRead = false));
- // Generate an internal plan for resource allocation.
+ // Generate an internal plan for resource allocation. After this you can optionally call
+ // `makeBudgetHeadroom` to check whether that plan would go over our memory budget.
// Fully-lazy proxies are also instantiated at this point so that their size can
// be known accurately. Returns false if any lazy proxy failed to instantiate, true otherwise.
bool planAssignment();
+ // Figure out how much VRAM headroom this plan requires. If there's enough purgeable resources,
+ // purge them and return true. Otherwise return false.
+ bool makeBudgetHeadroom();
+
// Instantiate and assign resources to all proxies.
bool assign();
@@ -143,6 +148,9 @@
const GrScratchKey& scratchKey() const { return fScratchKey; }
const GrUniqueKey& uniqueKey() const { return fOriginatingProxy->getUniqueKey(); }
+ bool accountedForInBudget() const { return fAccountedForInBudget; }
+ void setAccountedForInBudget() { fAccountedForInBudget = true; }
+
GrSurface* existingSurface() const { return fExistingSurface.get(); }
// Can this register be used by other proxies after this one?
@@ -159,6 +167,7 @@
GrSurfaceProxy* fOriginatingProxy;
GrScratchKey fScratchKey; // free pool wants a reference to this.
sk_sp<GrSurface> fExistingSurface; // queried from resource cache. may be null.
+ bool fAccountedForInBudget = false;
#ifdef SK_DEBUG
uint32_t fUniqueID;
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 94211f2..64d470c 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -622,22 +622,27 @@
bool GrResourceCache::purgeToMakeHeadroom(size_t desiredHeadroomBytes) {
AutoValidate av(this);
+ if (desiredHeadroomBytes > fMaxBytes) {
+ return false;
+ }
if (this->wouldFit(desiredHeadroomBytes)) {
return true;
}
fPurgeableQueue.sort();
- size_t headroom = this->overBudget() ? 0 : fMaxBytes - fBudgetedBytes;
+ size_t projectedBudget = fBudgetedBytes;
int purgeCnt = 0;
for (int i = 0; i < fPurgeableQueue.count(); i++) {
GrGpuResource* resource = fPurgeableQueue.at(i);
- headroom += resource->gpuMemorySize();
- if (headroom >= desiredHeadroomBytes) {
+ if (GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()) {
+ projectedBudget -= resource->gpuMemorySize();
+ }
+ if (projectedBudget + desiredHeadroomBytes <= fMaxBytes) {
purgeCnt = i + 1;
break;
}
}
- if (headroom < desiredHeadroomBytes) {
+ if (purgeCnt == 0) {
return false;
}