aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/gpu/GrDrawingManager.cpp10
-rw-r--r--src/gpu/GrOpList.h3
-rw-r--r--src/gpu/GrRenderTargetOpList.cpp19
-rw-r--r--src/gpu/GrRenderTargetOpList.h2
-rw-r--r--src/gpu/GrResourceAllocator.cpp13
-rw-r--r--src/gpu/GrResourceAllocator.h9
-rw-r--r--src/gpu/GrTextureOpList.cpp40
-rw-r--r--src/gpu/GrTextureOpList.h2
-rw-r--r--tests/LazyProxyTest.cpp91
-rw-r--r--tests/ResourceAllocatorTest.cpp8
10 files changed, 179 insertions, 18 deletions
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 302da06c07..616ac581e4 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -183,9 +183,17 @@ GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*,
startIndex = 0;
stopIndex = fOpLists.count();
#else
- while (alloc.assign(&startIndex, &stopIndex))
+ GrResourceAllocator::AssignError error = GrResourceAllocator::AssignError::kNoError;
+ while (alloc.assign(&startIndex, &stopIndex, &error))
#endif
{
+#ifndef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
+ if (GrResourceAllocator::AssignError::kFailedProxyInstantiation == error) {
+ for (int i = startIndex; i < stopIndex; ++i) {
+ fOpLists[i]->purgeOpsWithUninstantiatedProxies();
+ }
+ }
+#endif
if (this->executeOpLists(startIndex, stopIndex, &flushState)) {
flushed = true;
}
diff --git a/src/gpu/GrOpList.h b/src/gpu/GrOpList.h
index bcc1a01cbf..f1989fd591 100644
--- a/src/gpu/GrOpList.h
+++ b/src/gpu/GrOpList.h
@@ -126,6 +126,9 @@ protected:
private:
friend class GrDrawingManager; // for resetFlag, TopoSortTraits & gatherProxyIntervals
+ // Remove all Ops which reference proxies that have not been instantiated.
+ virtual void purgeOpsWithUninstantiatedProxies() = 0;
+
// Feed proxy usage intervals to the GrResourceAllocator class
virtual void gatherProxyIntervals(GrResourceAllocator*) const = 0;
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 0c806bfe2c..ccf2b78385 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -45,7 +45,7 @@ void GrRenderTargetOpList::dump() const {
for (int i = 0; i < fRecordedOps.count(); ++i) {
SkDebugf("*******************************\n");
if (!fRecordedOps[i].fOp) {
- SkDebugf("%d: <combined forward>\n", i);
+ SkDebugf("%d: <combined forward or failed instantiation>\n", i);
} else {
SkDebugf("%d: %s\n", i, fRecordedOps[i].fOp->name());
SkString str = fRecordedOps[i].fOp->dumpInfo();
@@ -238,6 +238,23 @@ bool GrRenderTargetOpList::copySurface(const GrCaps& caps,
return true;
}
+void GrRenderTargetOpList::purgeOpsWithUninstantiatedProxies() {
+ bool hasUninstantiatedProxy = false;
+ auto checkInstantiation = [ &hasUninstantiatedProxy ] (GrSurfaceProxy* p) {
+ if (!p->priv().isInstantiated()) {
+ hasUninstantiatedProxy = true;
+ }
+ };
+ for (RecordedOp& recordedOp : fRecordedOps) {
+ hasUninstantiatedProxy = false;
+ recordedOp.visitProxies(checkInstantiation);
+ if (hasUninstantiatedProxy) {
+ // When instantiation of the proxy fails we drop the Op
+ recordedOp.fOp = nullptr;
+ }
+ }
+}
+
void GrRenderTargetOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
unsigned int cur = alloc->numOps();
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index 6b736338f7..6bbd1cb837 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -143,6 +143,8 @@ private:
GrAppliedClip* fAppliedClip;
};
+ void purgeOpsWithUninstantiatedProxies() override;
+
void gatherProxyIntervals(GrResourceAllocator*) const override;
void recordOp(std::unique_ptr<GrOp>, const GrCaps& caps,
diff --git a/src/gpu/GrResourceAllocator.cpp b/src/gpu/GrResourceAllocator.cpp
index d346a7ee5b..6ed3d4dc43 100644
--- a/src/gpu/GrResourceAllocator.cpp
+++ b/src/gpu/GrResourceAllocator.cpp
@@ -195,7 +195,10 @@ void GrResourceAllocator::expire(unsigned int curIndex) {
}
}
-bool GrResourceAllocator::assign(int* startIndex, int* stopIndex) {
+bool GrResourceAllocator::assign(int* startIndex, int* stopIndex, AssignError* outError) {
+ SkASSERT(outError);
+ *outError = AssignError::kNoError;
+
fIntvlHash.reset(); // we don't need the interval hash anymore
if (fIntvlList.empty()) {
return false; // nothing to render
@@ -237,7 +240,9 @@ bool GrResourceAllocator::assign(int* startIndex, int* stopIndex) {
}
if (GrSurfaceProxy::LazyState::kNot != cur->proxy()->lazyInstantiationState()) {
- cur->proxy()->priv().doLazyInstantiation(fResourceProvider);
+ if (!cur->proxy()->priv().doLazyInstantiation(fResourceProvider)) {
+ *outError = AssignError::kFailedProxyInstantiation;
+ }
} else if (sk_sp<GrSurface> surface = this->findSurfaceFor(cur->proxy(), needsStencil)) {
// TODO: make getUniqueKey virtual on GrSurfaceProxy
GrTextureProxy* tex = cur->proxy()->asTextureProxy();
@@ -247,9 +252,11 @@ bool GrResourceAllocator::assign(int* startIndex, int* stopIndex) {
}
cur->assign(std::move(surface));
+ } else {
+ SkASSERT(!cur->proxy()->priv().isInstantiated());
+ *outError = AssignError::kFailedProxyInstantiation;
}
- // TODO: handle resource allocation failure upstack
fActiveIntvls.insertByIncreasingEnd(cur);
if (fResourceProvider->overBudget()) {
diff --git a/src/gpu/GrResourceAllocator.h b/src/gpu/GrResourceAllocator.h
index 6f0f09cb40..bbc577d47d 100644
--- a/src/gpu/GrResourceAllocator.h
+++ b/src/gpu/GrResourceAllocator.h
@@ -57,11 +57,18 @@ public:
this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
}
+ enum class AssignError {
+ kNoError,
+ kFailedProxyInstantiation
+ };
+
// Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
// false when nothing remains to be executed.
+ // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation.
+ // If this happens, the caller should remove all ops which reference an uninstantiated proxy.
// This is used to execute a portion of the queued opLists in order to reduce the total
// amount of GPU resources required.
- bool assign(int* startIndex, int* stopIndex);
+ bool assign(int* startIndex, int* stopIndex, AssignError* outError);
void markEndOfOpList(int opListIndex);
diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp
index c0de35fa1a..ad00d95a00 100644
--- a/src/gpu/GrTextureOpList.cpp
+++ b/src/gpu/GrTextureOpList.cpp
@@ -33,14 +33,18 @@ void GrTextureOpList::dump() const {
SkDebugf("ops (%d):\n", fRecordedOps.count());
for (int i = 0; i < fRecordedOps.count(); ++i) {
- SkDebugf("*******************************\n");
- SkDebugf("%d: %s\n", i, fRecordedOps[i]->name());
- SkString str = fRecordedOps[i]->dumpInfo();
- SkDebugf("%s\n", str.c_str());
- const SkRect& clippedBounds = fRecordedOps[i]->bounds();
- SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
- clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
- clippedBounds.fBottom);
+ if (!fRecordedOps[i]) {
+ SkDebugf("%d: <failed instantiation>\n", i);
+ } else {
+ SkDebugf("*******************************\n");
+ SkDebugf("%d: %s\n", i, fRecordedOps[i]->name());
+ SkString str = fRecordedOps[i]->dumpInfo();
+ SkDebugf("%s\n", str.c_str());
+ const SkRect& clippedBounds = fRecordedOps[i]->bounds();
+ SkDebugf("ClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
+ clippedBounds.fLeft, clippedBounds.fTop, clippedBounds.fRight,
+ clippedBounds.fBottom);
+ }
}
}
@@ -123,6 +127,26 @@ bool GrTextureOpList::copySurface(const GrCaps& caps,
return true;
}
+void GrTextureOpList::purgeOpsWithUninstantiatedProxies() {
+ bool hasUninstantiatedProxy = false;
+ auto checkInstantiation = [ &hasUninstantiatedProxy ] (GrSurfaceProxy* p) {
+ if (!p->priv().isInstantiated()) {
+ hasUninstantiatedProxy = true;
+ }
+ };
+ for (int i = 0; i < fRecordedOps.count(); ++i) {
+ const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version
+ hasUninstantiatedProxy = false;
+ if (op) {
+ op->visitProxies(checkInstantiation);
+ }
+ if (hasUninstantiatedProxy) {
+ // When instantiation of the proxy fails we drop the Op
+ fRecordedOps[i] = nullptr;
+ }
+ }
+}
+
void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const {
unsigned int cur = alloc->numOps();
diff --git a/src/gpu/GrTextureOpList.h b/src/gpu/GrTextureOpList.h
index aa9cb2ea1f..42da738390 100644
--- a/src/gpu/GrTextureOpList.h
+++ b/src/gpu/GrTextureOpList.h
@@ -61,6 +61,8 @@ public:
SkDEBUGCODE(int numOps() const override { return fRecordedOps.count(); })
private:
+ void purgeOpsWithUninstantiatedProxies() override;
+
void gatherProxyIntervals(GrResourceAllocator*) const override;
void recordOp(std::unique_ptr<GrOp>);
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index d43f07d959..029a5a5ed1 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -194,14 +194,16 @@ DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
}
}
+static const int kSize = 16;
+
DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
GrMockOptions mockOptions;
sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
auto proxyProvider = ctx->contextPriv().proxyProvider();
GrSurfaceDesc desc;
- desc.fWidth = 16;
- desc.fHeight = 16;
+ desc.fWidth = kSize;
+ desc.fHeight = kSize;
desc.fConfig = kRGBA_8888_GrPixelConfig;
for (bool doInstantiate : {true, false}) {
@@ -231,4 +233,89 @@ DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
}
}
+class LazyFailedInstantiationTestOp : public GrDrawOp {
+public:
+ DEFINE_OP_CLASS_ID
+
+ LazyFailedInstantiationTestOp(GrProxyProvider* proxyProvider, int* testExecuteValue,
+ bool shouldFailInstantiation)
+ : INHERITED(ClassID())
+ , fTestExecuteValue(testExecuteValue) {
+ GrSurfaceDesc desc;
+ desc.fWidth = kSize;
+ desc.fHeight = kSize;
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+
+ fLazyProxy = proxyProvider->createLazyProxy(
+ [testExecuteValue, shouldFailInstantiation, desc] (
+ GrResourceProvider* rp, GrSurfaceOrigin* /*origin*/) {
+ *testExecuteValue = 1;
+ if (shouldFailInstantiation || !rp) {
+ return sk_sp<GrTexture>();
+ }
+ return rp->createTexture(desc, SkBudgeted::kNo);
+ }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
+
+ this->setBounds(SkRect::MakeIWH(kSize, kSize),
+ HasAABloat::kNo, IsZeroArea::kNo);
+ }
+
+ void visitProxies(const VisitProxyFunc& func) const override {
+ func(fLazyProxy.get());
+ }
+
+private:
+ const char* name() const override { return "LazyFailedInstantiationTestOp"; }
+ FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
+ RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
+ GrPixelConfigIsClamped) override {
+ return RequiresDstTexture::kNo;
+ }
+ bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
+ void onPrepare(GrOpFlushState*) override {}
+ void onExecute(GrOpFlushState* state) override {
+ *fTestExecuteValue = 2;
+ }
+
+ int* fTestExecuteValue;
+ sk_sp<GrSurfaceProxy> fLazyProxy;
+
+ typedef GrDrawOp INHERITED;
+};
+
+// Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
+// associated with.
+DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) {
+ GrMockOptions mockOptions;
+ sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
+ GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
+ for (bool failInstantiation : {false, true}) {
+ sk_sp<GrRenderTargetContext> rtc =
+ ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
+ kRGBA_8888_GrPixelConfig, nullptr);
+ REPORTER_ASSERT(reporter, rtc);
+
+ rtc->clear(nullptr, 0xbaaaaaad, GrRenderTargetContext::CanClearFullscreen::kYes);
+
+ int executeTestValue = 0;
+ rtc->priv().testingOnly_addDrawOp(
+ skstd::make_unique<LazyFailedInstantiationTestOp>(proxyProvider, &executeTestValue,
+ failInstantiation));
+ ctx->flush();
+
+ if (failInstantiation) {
+#ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
+ // When we disable explicit gpu resource allocation we don't throw away ops that have
+ // uninstantiated proxies.
+ REPORTER_ASSERT(reporter, 2 == executeTestValue);
+#else
+ REPORTER_ASSERT(reporter, 1 == executeTestValue);
+#endif
+ } else {
+ REPORTER_ASSERT(reporter, 2 == executeTestValue);
+ }
+ }
+
+}
+
#endif
diff --git a/tests/ResourceAllocatorTest.cpp b/tests/ResourceAllocatorTest.cpp
index 121cf86345..7dcb0ee942 100644
--- a/tests/ResourceAllocatorTest.cpp
+++ b/tests/ResourceAllocatorTest.cpp
@@ -72,7 +72,9 @@ static void overlap_test(skiatest::Reporter* reporter, GrResourceProvider* resou
alloc.markEndOfOpList(0);
int startIndex, stopIndex;
- alloc.assign(&startIndex, &stopIndex);
+ GrResourceAllocator::AssignError error;
+ alloc.assign(&startIndex, &stopIndex, &error);
+ REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
REPORTER_ASSERT(reporter, p1->priv().peekSurface());
REPORTER_ASSERT(reporter, p2->priv().peekSurface());
@@ -92,7 +94,9 @@ static void non_overlap_test(skiatest::Reporter* reporter, GrResourceProvider* r
alloc.markEndOfOpList(0);
int startIndex, stopIndex;
- alloc.assign(&startIndex, &stopIndex);
+ GrResourceAllocator::AssignError error;
+ alloc.assign(&startIndex, &stopIndex, &error);
+ REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
REPORTER_ASSERT(reporter, p1->priv().peekSurface());
REPORTER_ASSERT(reporter, p2->priv().peekSurface());