diff options
-rw-r--r-- | src/gpu/GrDrawingManager.cpp | 10 | ||||
-rw-r--r-- | src/gpu/GrOpList.h | 3 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.cpp | 19 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.h | 2 | ||||
-rw-r--r-- | src/gpu/GrResourceAllocator.cpp | 13 | ||||
-rw-r--r-- | src/gpu/GrResourceAllocator.h | 9 | ||||
-rw-r--r-- | src/gpu/GrTextureOpList.cpp | 40 | ||||
-rw-r--r-- | src/gpu/GrTextureOpList.h | 2 | ||||
-rw-r--r-- | tests/LazyProxyTest.cpp | 91 | ||||
-rw-r--r-- | tests/ResourceAllocatorTest.cpp | 8 |
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()); |