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>
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 4c5cb85..94211f2 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -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 @@
     }
 }
 
+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);