From 706a6ff60c55bee85cff06fc9f8f3764f6e5154b Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Wed, 29 Nov 2017 22:01:06 -0700 Subject: Add "lazy" texture proxies Adds ultra-deferred proxies that are instantiated by a user-supplied callback during flush. Bug: skia:7190 Change-Id: I75a7ac6dba953c3b0a99febc203a7f4d2f3789fc Reviewed-on: https://skia-review.googlesource.com/76461 Commit-Queue: Chris Dalton Reviewed-by: Robert Phillips --- src/gpu/GrDrawingManager.cpp | 12 ++++++- src/gpu/GrRenderTargetContextPriv.h | 1 + src/gpu/GrRenderTargetOpList.cpp | 6 ++++ src/gpu/GrRenderTargetOpList.h | 1 + src/gpu/GrRenderTargetProxy.cpp | 20 +++++++---- src/gpu/GrResourceAllocator.cpp | 12 +++++-- src/gpu/GrSurfaceProxy.cpp | 62 +++++++++++++++++++++++++++++++++- src/gpu/GrSurfaceProxyPriv.h | 2 ++ src/gpu/GrTextureProxy.cpp | 22 ++++++++++-- src/gpu/GrTextureRenderTargetProxy.cpp | 40 +++++++++++++++++----- src/gpu/GrTextureRenderTargetProxy.h | 5 +++ 11 files changed, 162 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp index d95a2c5c70..bf8d1abbcf 100644 --- a/src/gpu/GrDrawingManager.cpp +++ b/src/gpu/GrDrawingManager.cpp @@ -21,6 +21,8 @@ #include "GrSurfaceProxyPriv.h" #include "GrTextureContext.h" #include "GrTextureOpList.h" +#include "GrTextureProxy.h" +#include "GrTextureProxyPriv.h" #include "SkSurface_Gpu.h" #include "SkTTopoSort.h" @@ -150,10 +152,18 @@ GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*, fFlushingOpListIDs.begin(), fFlushingOpListIDs.count(), &renderTargetContexts); for (const sk_sp& rtc : renderTargetContexts) { - sk_sp onFlushOpList = sk_ref_sp(rtc->getOpList()); + sk_sp onFlushOpList = sk_ref_sp(rtc->getRTOpList()); if (!onFlushOpList) { continue; // Odd - but not a big deal } +#ifdef SK_DEBUG + // OnFlush callbacks are already invoked during flush, and are therefore expected to + // handle resource allocation & usage on their own. (No deferred or lazy proxies!) + onFlushOpList->visitProxies_debugOnly([](GrSurfaceProxy* p) { + SkASSERT(!p->asTextureProxy() || !p->asTextureProxy()->texPriv().isDeferred()); + SkASSERT(!p->isPendingLazyInstantiation()); + }); +#endif onFlushOpList->makeClosed(*fContext->caps()); onFlushOpList->prepare(&fFlushState); fOnFlushCBOpLists.push_back(std::move(onFlushOpList)); diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h index 0d73793c9d..271badb64c 100644 --- a/src/gpu/GrRenderTargetContextPriv.h +++ b/src/gpu/GrRenderTargetContextPriv.h @@ -109,6 +109,7 @@ public: } uint32_t testingOnly_addDrawOp(std::unique_ptr); + uint32_t testingOnly_addDrawOp(const GrClip&, std::unique_ptr); bool refsWrappedObjects() const { return fRenderTargetContext->fRenderTargetProxy->refsWrappedObjects(); diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 885723c0d6..ff85a41afe 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -60,6 +60,12 @@ void GrRenderTargetOpList::dump() const { } } } + +void GrRenderTargetOpList::visitProxies_debugOnly(const GrOp::VisitProxyFunc& func) const { + for (const RecordedOp& recordedOp : fRecordedOps) { + recordedOp.visitProxies(func); + } +} #endif void GrRenderTargetOpList::onPrepare(GrOpFlushState* flushState) { diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h index 7e600d41d1..93bab91051 100644 --- a/src/gpu/GrRenderTargetOpList.h +++ b/src/gpu/GrRenderTargetOpList.h @@ -125,6 +125,7 @@ public: SkDEBUGCODE(int numOps() const override { return fRecordedOps.count(); }) SkDEBUGCODE(int numClips() const override { return fNumClips; }) + SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const;) private: friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp index 9453ce8204..dea47e6b5c 100644 --- a/src/gpu/GrRenderTargetProxy.cpp +++ b/src/gpu/GrRenderTargetProxy.cpp @@ -34,12 +34,20 @@ GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, const GrSurfaceDesc } } +// Lazy-callback version +GrRenderTargetProxy::GrRenderTargetProxy(LazyInstantiateCallback&& callback, GrPixelConfig config) + : INHERITED(std::move(callback), config) + , fSampleCnt(0) + , fNeedsStencil(false) + , fRenderTargetFlags(GrRenderTargetFlags::kNone) { +} + // Wrapped version GrRenderTargetProxy::GrRenderTargetProxy(sk_sp surf, GrSurfaceOrigin origin) - : INHERITED(std::move(surf), origin, SkBackingFit::kExact) - , fSampleCnt(fTarget->asRenderTarget()->numStencilSamples()) - , fNeedsStencil(false) - , fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) { + : INHERITED(std::move(surf), origin, SkBackingFit::kExact) + , fSampleCnt(fTarget->asRenderTarget()->numStencilSamples()) + , fNeedsStencil(false) + , fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) { } int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const { @@ -85,8 +93,8 @@ size_t GrRenderTargetProxy::onUninstantiatedGpuMemorySize() const { int colorSamplesPerPixel = this->numColorSamples() + 1; // TODO: do we have enough information to improve this worst case estimate? - return GrSurface::ComputeSize(fConfig, fWidth, fHeight, colorSamplesPerPixel, GrMipMapped::kNo, - SkBackingFit::kApprox == fFit); + return GrSurface::ComputeSize(this->config(), this->width(), this->height(), + colorSamplesPerPixel, GrMipMapped::kNo, !this->priv().isExact()); } bool GrRenderTargetProxy::refsWrappedObjects() const { diff --git a/src/gpu/GrResourceAllocator.cpp b/src/gpu/GrResourceAllocator.cpp index 0afc0ed8c9..bf46c61e8e 100644 --- a/src/gpu/GrResourceAllocator.cpp +++ b/src/gpu/GrResourceAllocator.cpp @@ -73,6 +73,13 @@ void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy, unsigned int start, fIntvlList.insertByIncreasingStart(newIntvl); fIntvlHash.add(newIntvl); + +#ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION + // FIXME: remove this once we can do the lazy instantiation from assign instead. + if (proxy->isPendingLazyInstantiation()) { + proxy->priv().doLazyInstantiation(fResourceProvider); + } +#endif } GrResourceAllocator::Interval* GrResourceAllocator::IntervalList::popHead() { @@ -224,8 +231,9 @@ bool GrResourceAllocator::assign(int* startIndex, int* stopIndex) { continue; } - sk_sp surface = this->findSurfaceFor(cur->proxy(), needsStencil); - if (surface) { + if (cur->proxy()->isPendingLazyInstantiation()) { + cur->proxy()->priv().doLazyInstantiation(fResourceProvider); + } else if (sk_sp surface = this->findSurfaceFor(cur->proxy(), needsStencil)) { // TODO: make getUniqueKey virtual on GrSurfaceProxy GrTextureProxy* tex = cur->proxy()->asTextureProxy(); if (tex && tex->getUniqueKey().isValid()) { diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp index 71ff6374ff..a5c2be622b 100644 --- a/src/gpu/GrSurfaceProxy.cpp +++ b/src/gpu/GrSurfaceProxy.cpp @@ -21,6 +21,23 @@ #include "SkMathPriv.h" #include "SkMipMap.h" +// Lazy-callback version +GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, GrPixelConfig config) + : fConfig(config) + , fWidth(-1) // Width, height, and origin will be initialized upon lazy instantiation. + , fHeight(-1) + , fOrigin(kGrUnknownSurfaceOrigin) + , fFit(SkBackingFit::kApprox) + , fBudgeted(SkBudgeted::kYes) + , fFlags(GrResourceProvider::kNoPendingIO_Flag) + , fLazyInstantiateCallback(std::move(callback)) + , fNeedsClear(false) + , fGpuMemorySize(kInvalidGpuMemorySize) + , fLastOpList(nullptr) { + // NOTE: the default fUniqueID ctor pulls a value from the same pool as the GrGpuResources. +} + +// Wrapped version GrSurfaceProxy::GrSurfaceProxy(sk_sp surface, GrSurfaceOrigin origin, SkBackingFit fit) : INHERITED(std::move(surface)) , fConfig(fTarget->config()) @@ -64,6 +81,7 @@ sk_sp GrSurfaceProxy::createSurfaceImpl( int sampleCnt, bool needsStencil, GrSurfaceFlags flags, GrMipMapped mipMapped, SkDestinationSurfaceColorMode mipColorMode) const { + SkASSERT(!this->isPendingLazyInstantiation()); SkASSERT(GrMipMapped::kNo == mipMapped); GrSurfaceDesc desc; desc.fFlags = flags; @@ -96,6 +114,7 @@ sk_sp GrSurfaceProxy::createSurfaceImpl( } void GrSurfaceProxy::assign(sk_sp surface) { + SkASSERT(!this->isPendingLazyInstantiation()); SkASSERT(!fTarget && surface); fTarget = surface.release(); this->INHERITED::transferRefs(); @@ -111,6 +130,7 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s bool needsStencil, GrSurfaceFlags flags, GrMipMapped mipMapped, SkDestinationSurfaceColorMode mipColorMode, const GrUniqueKey* uniqueKey) { + SkASSERT(!this->isPendingLazyInstantiation()); if (fTarget) { if (uniqueKey) { SkASSERT(fTarget->getUniqueKey() == *uniqueKey); @@ -135,6 +155,7 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s } void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const { + SkASSERT(!this->isPendingLazyInstantiation()); const GrRenderTargetProxy* rtp = this->asRenderTargetProxy(); int sampleCount = 0; if (rtp) { @@ -377,7 +398,15 @@ sk_sp GrSurfaceProxy::MakeWrappedBackend(GrContext* context, return GrSurfaceProxy::MakeWrapped(std::move(tex), origin); } +sk_sp GrSurfaceProxy::MakeLazy(LazyInstantiateCallback&& callback, + Renderable renderable, GrPixelConfig config) { + return sk_sp(Renderable::kYes == renderable ? + new GrTextureRenderTargetProxy(std::move(callback), config) : + new GrTextureProxy(std::move(callback), config)); +} + int GrSurfaceProxy::worstCaseWidth() const { + SkASSERT(!this->isPendingLazyInstantiation()); if (fTarget) { return fTarget->width(); } @@ -389,6 +418,7 @@ int GrSurfaceProxy::worstCaseWidth() const { } int GrSurfaceProxy::worstCaseHeight() const { + SkASSERT(!this->isPendingLazyInstantiation()); if (fTarget) { return fTarget->height(); } @@ -414,6 +444,7 @@ sk_sp GrSurfaceProxy::Copy(GrContext* context, GrMipMapped mipMapped, SkIRect srcRect, SkBudgeted budgeted) { + SkASSERT(!src->isPendingLazyInstantiation()); if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) { return nullptr; } @@ -442,12 +473,13 @@ sk_sp GrSurfaceProxy::Copy(GrContext* context, sk_sp GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src, GrMipMapped mipMapped, SkBudgeted budgeted) { + SkASSERT(!src->isPendingLazyInstantiation()); return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), budgeted); } sk_sp GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, GrSurfaceProxy* srcProxy) { - + SkASSERT(!srcProxy->isPendingLazyInstantiation()); sk_sp dstContext(context->contextPriv().makeDeferredSurfaceContext( dstDesc, GrMipMapped::kNo, @@ -465,6 +497,7 @@ sk_sp GrSurfaceProxy::TestCopy(GrContext* context, const GrSur } void GrSurfaceProxyPriv::exactify() { + SkASSERT(!fProxy->isPendingLazyInstantiation()); if (this->isExact()) { return; } @@ -491,3 +524,30 @@ void GrSurfaceProxyPriv::exactify() { // exact amount. } +void GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) { + SkASSERT(fProxy->fLazyInstantiateCallback); + SkASSERT(!fProxy->fTarget); + + sk_sp texture = fProxy->fLazyInstantiateCallback(resourceProvider, &fProxy->fOrigin); + + // Indicate we are no longer pending lazy instantiation. + fProxy->fLazyInstantiateCallback = nullptr; + + if (!texture) { + fProxy->fWidth = 0; + fProxy->fHeight = 0; + fProxy->fOrigin = kTopLeft_GrSurfaceOrigin; + return; + } + + fProxy->fWidth = texture->width(); + fProxy->fHeight = texture->height(); + + SkASSERT(texture->config() == fProxy->fConfig); + SkASSERT(kGrUnknownSurfaceOrigin != fProxy->origin()); + SkASSERT(kTopLeft_GrSurfaceOrigin == fProxy->fOrigin || + kBottomLeft_GrSurfaceOrigin == fProxy->fOrigin); + SkDEBUGCODE(fProxy->validateLazyTexture(texture.get());) + this->assign(std::move(texture)); +} + diff --git a/src/gpu/GrSurfaceProxyPriv.h b/src/gpu/GrSurfaceProxyPriv.h index a93a20c051..b4811b68c8 100644 --- a/src/gpu/GrSurfaceProxyPriv.h +++ b/src/gpu/GrSurfaceProxyPriv.h @@ -68,6 +68,8 @@ public: // Don't. Just don't. void exactify(); + void doLazyInstantiation(GrResourceProvider*); + static bool AttachStencilIfNeeded(GrResourceProvider*, GrSurface*, bool needsStencil); private: diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp index 9afa63f374..9b3dc9cb53 100644 --- a/src/gpu/GrTextureProxy.cpp +++ b/src/gpu/GrTextureProxy.cpp @@ -13,6 +13,7 @@ #include "GrResourceCache.h" #include "GrTexturePriv.h" +// Deferred version GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, SkBudgeted budgeted, const void* srcData, size_t /*rowBytes*/, uint32_t flags) : INHERITED(srcDesc, fit, budgeted, flags) @@ -23,6 +24,16 @@ GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, S SkASSERT(!srcData); // currently handled in Make() } +// Lazy-callback version +GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, GrPixelConfig config) + : INHERITED(std::move(callback), config) + , fMipMapped(GrMipMapped::kNo) + , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) + , fCache(nullptr) + , fDeferredUploader(nullptr) { +} + +// Wrapped version GrTextureProxy::GrTextureProxy(sk_sp surf, GrSurfaceOrigin origin) : INHERITED(std::move(surf), origin, SkBackingFit::kExact) , fMipMapped(fTarget->asTexture()->texturePriv().mipMapped()) @@ -109,8 +120,8 @@ GrSamplerState::Filter GrTextureProxy::highestFilterMode() const { } size_t GrTextureProxy::onUninstantiatedGpuMemorySize() const { - return GrSurface::ComputeSize(fConfig, fWidth, fHeight, 1, this->mipMapped(), - SkBackingFit::kApprox == fFit); + return GrSurface::ComputeSize(this->config(), this->width(), this->height(), 1, + this->mipMapped(), !this->priv().isExact()); } void GrTextureProxy::setUniqueKey(GrResourceCache* cache, const GrUniqueKey& key) { @@ -131,3 +142,10 @@ void GrTextureProxy::clearUniqueKey() { fCache = nullptr; } +#ifdef SK_DEBUG +void GrTextureProxy::validateLazyTexture(const GrTexture* texture) { + SkASSERT(!texture->asRenderTarget()); + SkASSERT(GrMipMapped::kNo == this->mipMapped()); +} +#endif + diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp index dd79bfefff..943523116d 100644 --- a/src/gpu/GrTextureRenderTargetProxy.cpp +++ b/src/gpu/GrTextureRenderTargetProxy.cpp @@ -7,6 +7,10 @@ #include "GrTextureRenderTargetProxy.h" +#include "GrTexture.h" +#include "GrRenderTarget.h" +#include "GrSurfaceProxyPriv.h" + // Deferred version // This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and // GrRenderTargetProxy) so its constructor must be explicitly called. @@ -15,10 +19,20 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags) - : GrSurfaceProxy(desc, fit, budgeted, flags) - // for now textures w/ data are always wrapped - , GrTextureProxy(desc, fit, budgeted, nullptr, 0, flags) - , GrRenderTargetProxy(caps, desc, fit, budgeted, flags) { + : GrSurfaceProxy(desc, fit, budgeted, flags) + // for now textures w/ data are always wrapped + , GrTextureProxy(desc, fit, budgeted, nullptr, 0, flags) + , GrRenderTargetProxy(caps, desc, fit, budgeted, flags) { +} + +// Lazy-callback version +GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(LazyInstantiateCallback&& callback, + GrPixelConfig config) + : GrSurfaceProxy(std::move(callback), config) + // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null + // callbacks to the texture and RT proxies simply to route to the appropriate constructors. + , GrTextureProxy(LazyInstantiateCallback(), config) + , GrRenderTargetProxy(LazyInstantiateCallback(), config) { } // Wrapped version @@ -26,9 +40,9 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, // GrRenderTargetProxy) so its constructor must be explicitly called. GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp surf, GrSurfaceOrigin origin) - : GrSurfaceProxy(surf, origin, SkBackingFit::kExact) - , GrTextureProxy(surf, origin) - , GrRenderTargetProxy(surf, origin) { + : GrSurfaceProxy(surf, origin, SkBackingFit::kExact) + , GrTextureProxy(surf, origin) + , GrRenderTargetProxy(surf, origin) { SkASSERT(surf->asTexture()); SkASSERT(surf->asRenderTarget()); } @@ -37,8 +51,8 @@ size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const { int colorSamplesPerPixel = this->numColorSamples() + 1; // TODO: do we have enough information to improve this worst case estimate? - return GrSurface::ComputeSize(fConfig, fWidth, fHeight, colorSamplesPerPixel, this->mipMapped(), - SkBackingFit::kApprox == fFit); + return GrSurface::ComputeSize(this->config(), this->width(), this->height(), + colorSamplesPerPixel, this->mipMapped(), !this->priv().isExact()); } bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) { @@ -77,3 +91,11 @@ sk_sp GrTextureRenderTargetProxy::createSurface( return surface; } +#ifdef SK_DEBUG +void GrTextureRenderTargetProxy::validateLazyTexture(const GrTexture* texture) { + SkASSERT(texture->asRenderTarget()); + SkASSERT(texture->asRenderTarget()->numStencilSamples() == this->numStencilSamples()); + SkASSERT(GrMipMapped::kNo == this->mipMapped()); +} +#endif + diff --git a/src/gpu/GrTextureRenderTargetProxy.h b/src/gpu/GrTextureRenderTargetProxy.h index 7005169b22..5719366954 100644 --- a/src/gpu/GrTextureRenderTargetProxy.h +++ b/src/gpu/GrTextureRenderTargetProxy.h @@ -29,6 +29,9 @@ private: GrTextureRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&, SkBackingFit, SkBudgeted, uint32_t flags); + // Lazy-callback version + GrTextureRenderTargetProxy(LazyInstantiateCallback&&, GrPixelConfig); + // Wrapped version GrTextureRenderTargetProxy(sk_sp, GrSurfaceOrigin); @@ -36,6 +39,8 @@ private: sk_sp createSurface(GrResourceProvider*) const override; size_t onUninstantiatedGpuMemorySize() const override; + + SkDEBUGCODE(void validateLazyTexture(const GrTexture*) override;) }; #ifdef SK_BUILD_FOR_WIN -- cgit v1.2.3