From f290376736b42a19b87da78c6ba2558313896860 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Wed, 8 Nov 2017 13:34:43 -0500 Subject: Prepare to enable explicit gpu resource allocation Change-Id: I407e45711c61831febbac3d3d3a88e3fdde92c5f Reviewed-on: https://skia-review.googlesource.com/68212 Commit-Queue: Robert Phillips Reviewed-by: Brian Salomon --- src/gpu/GrDrawingManager.cpp | 12 ++-- src/gpu/GrRenderTargetOpList.cpp | 20 ++++--- src/gpu/GrResourceAllocator.cpp | 119 +++++++++++++++++++-------------------- src/gpu/GrResourceAllocator.h | 17 +++++- src/gpu/GrResourceCache.h | 1 + src/gpu/GrSurface.cpp | 17 ++++-- src/gpu/GrSurfaceProxyPriv.h | 6 ++ src/gpu/GrTextureOpList.cpp | 20 ++++--- src/gpu/effects/GrArithmeticFP.h | 2 +- 9 files changed, 129 insertions(+), 85 deletions(-) (limited to 'src/gpu') diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp index eaacac246e..1aaa6f7ad2 100644 --- a/src/gpu/GrDrawingManager.cpp +++ b/src/gpu/GrDrawingManager.cpp @@ -171,14 +171,16 @@ GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*, } #endif - GrResourceAllocator alloc(fContext->resourceProvider()); - for (int i = 0; i < fOpLists.count(); ++i) { - fOpLists[i]->gatherProxyIntervals(&alloc); - } + { + GrResourceAllocator alloc(fContext->resourceProvider()); + for (int i = 0; i < fOpLists.count(); ++i) { + fOpLists[i]->gatherProxyIntervals(&alloc); + } #ifdef MDB_ALLOC_RESOURCES - alloc.assign(); + alloc.assign(); #endif + } for (int i = 0; i < fOpLists.count(); ++i) { if (!fOpLists[i]->instantiate(fContext->resourceProvider())) { diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 09486c7c99..e6b91ff9c6 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -257,14 +257,18 @@ bool GrRenderTargetOpList::copySurface(const GrCaps& caps, } void GrRenderTargetOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const { - if (!fRecordedOps.count()) { - return; - } - unsigned int cur = alloc->numOps(); // Add the interval for all the writes to this opList's target - alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1); + if (fRecordedOps.count()) { + alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1); + } else { + // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we + // still need to add an interval for the destination so we create a fake op# for + // the missing clear op. + alloc->addInterval(fTarget.get()); + alloc->incOps(); + } auto gather = [ alloc ] (GrSurfaceProxy* p) { alloc->addInterval(p); @@ -273,9 +277,11 @@ void GrRenderTargetOpList::gatherProxyIntervals(GrResourceAllocator* alloc) cons const GrOp* op = fRecordedOps[i].fOp.get(); // only diff from the GrTextureOpList version if (op) { op->visitProxies(gather); - - alloc->incOps(); } + + // Even though the op may have been moved we still need to increment the op count to + // keep all the math consistent. + alloc->incOps(); } } diff --git a/src/gpu/GrResourceAllocator.cpp b/src/gpu/GrResourceAllocator.cpp index 62f780b177..f263802448 100644 --- a/src/gpu/GrResourceAllocator.cpp +++ b/src/gpu/GrResourceAllocator.cpp @@ -7,8 +7,12 @@ #include "GrResourceAllocator.h" +#include "GrGpuResourcePriv.h" +#include "GrResourceProvider.h" +#include "GrSurfacePriv.h" #include "GrSurfaceProxy.h" #include "GrSurfaceProxyPriv.h" +#include "GrTextureProxy.h" void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) { @@ -17,15 +21,18 @@ void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy, if (Interval* intvl = fIntvlHash.find(proxy->uniqueID().asUInt())) { // Revise the interval for an existing use - //SkASSERT(intvl->fEnd <= end); - intvl->fEnd = end; + // TODO: this assert is failing on the copy_on_write_retain GM! + //SkASSERT(intvl->end() <= start); + if (intvl->end() < end) { + intvl->extendEnd(end); + } return; } Interval* newIntvl; if (fFreeIntervalList) { newIntvl = fFreeIntervalList; - fFreeIntervalList = newIntvl->fNext; + fFreeIntervalList = newIntvl->next(); newIntvl->resetTo(proxy, start, end); } else { newIntvl = fIntervalAllocator.make(proxy, start, end); @@ -38,7 +45,7 @@ void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy, GrResourceAllocator::Interval* GrResourceAllocator::IntervalList::popHead() { Interval* temp = fHead; if (temp) { - fHead = temp->fNext; + fHead = temp->next(); } return temp; } @@ -46,36 +53,36 @@ GrResourceAllocator::Interval* GrResourceAllocator::IntervalList::popHead() { // TODO: fuse this with insertByIncreasingEnd void GrResourceAllocator::IntervalList::insertByIncreasingStart(Interval* intvl) { if (!fHead) { - intvl->fNext = nullptr; + intvl->setNext(nullptr); fHead = intvl; - } else if (intvl->fStart <= fHead->fStart) { - intvl->fNext = fHead; + } else if (intvl->start() <= fHead->start()) { + intvl->setNext(fHead); fHead = intvl; } else { Interval* prev = fHead; - Interval* next = prev->fNext; - for (; next && intvl->fStart > next->fStart; prev = next, next = next->fNext) { + Interval* next = prev->next(); + for (; next && intvl->start() > next->start(); prev = next, next = next->next()) { } - intvl->fNext = next; - prev->fNext = intvl; + intvl->setNext(next); + prev->setNext(intvl); } } // TODO: fuse this with insertByIncreasingStart void GrResourceAllocator::IntervalList::insertByIncreasingEnd(Interval* intvl) { if (!fHead) { - intvl->fNext = nullptr; + intvl->setNext(nullptr); fHead = intvl; - } else if (intvl->fEnd <= fHead->fEnd) { - intvl->fNext = fHead; + } else if (intvl->end() <= fHead->end()) { + intvl->setNext(fHead); fHead = intvl; } else { Interval* prev = fHead; - Interval* next = prev->fNext; - for (; next && intvl->fEnd > next->fEnd; prev = next, next = next->fNext) { + Interval* next = prev->next(); + for (; next && intvl->end() > next->end(); prev = next, next = next->next()) { } - intvl->fNext = next; - prev->fNext = intvl; + intvl->setNext(next); + prev->setNext(intvl); } } @@ -87,8 +94,15 @@ void GrResourceAllocator::freeUpSurface(GrSurface* surface) { return; // can't do it w/o a valid scratch key } + if (surface->getUniqueKey().isValid()) { + // If the surface has a unique key we throw it back into the resource cache. + // If things get really tight 'findSurfaceFor' may pull it back out but there is + // no need to have it in tight rotation. + return; + } + // TODO: fix this insertion so we get a more LRU-ish behavior - fFreePool.insert(key, surface); + fFreePool.insert(key, SkRef(surface)); } // First try to reuse one of the recently allocated/used GrSurfaces in the free pool. @@ -100,9 +114,19 @@ sk_sp GrResourceAllocator::findSurfaceFor(const GrSurfaceProxy* proxy proxy->priv().computeScratchKey(&key); - GrSurface* surface = fFreePool.find(key); + auto filter = [&] (const GrSurface* s) { + return !proxy->priv().requiresNoPendingIO() || !s->surfacePriv().hasPendingIO(); + }; + sk_sp surface(fFreePool.findAndRemove(key, filter)); if (surface) { - return sk_ref_sp(surface); + if (SkBudgeted::kYes == proxy->isBudgeted() && + SkBudgeted::kNo == surface->resourcePriv().isBudgeted()) { + // This gets the job done but isn't quite correct. It would be better to try to + // match budgeted proxies w/ budgeted surface and unbudgeted w/ unbudgeted. + surface->resourcePriv().makeBudgeted(); + } + + return surface; } // Failing that, try to grab a new one from the resource cache @@ -112,12 +136,12 @@ sk_sp GrResourceAllocator::findSurfaceFor(const GrSurfaceProxy* proxy // Remove any intervals that end before the current index. Return their GrSurfaces // to the free pool. void GrResourceAllocator::expire(unsigned int curIndex) { - while (!fActiveIntvls.empty() && fActiveIntvls.peekHead()->fEnd < curIndex) { + while (!fActiveIntvls.empty() && fActiveIntvls.peekHead()->end() < curIndex) { Interval* temp = fActiveIntvls.popHead(); - this->freeUpSurface(temp->fProxy->priv().peekSurface()); + this->freeUpSurface(temp->proxy()->priv().peekSurface()); // Add temp to the free interval list so it can be reused - temp->fNext = fFreeIntervalList; + temp->setNext(fFreeIntervalList); fFreeIntervalList = temp; } } @@ -127,51 +151,26 @@ void GrResourceAllocator::assign() { SkDEBUGCODE(fAssigned = true;) while (Interval* cur = fIntvlList.popHead()) { - this->expire(cur->fStart); + this->expire(cur->start()); - if (cur->fProxy->priv().isInstantiated()) { + if (cur->proxy()->priv().isInstantiated()) { fActiveIntvls.insertByIncreasingEnd(cur); continue; } // TODO: add over budget handling here? - sk_sp surface = this->findSurfaceFor(cur->fProxy); + sk_sp surface = this->findSurfaceFor(cur->proxy()); if (surface) { - cur->fProxy->priv().assign(std::move(surface)); + // TODO: make getUniqueKey virtual on GrSurfaceProxy + GrTextureProxy* tex = cur->proxy()->asTextureProxy(); + if (tex && tex->getUniqueKey().isValid()) { + fResourceProvider->assignUniqueKeyToResource(tex->getUniqueKey(), surface.get()); + SkASSERT(surface->getUniqueKey() == tex->getUniqueKey()); + } + + cur->proxy()->priv().assign(std::move(surface)); } // TODO: handle resouce allocation failure upstack fActiveIntvls.insertByIncreasingEnd(cur); } } - -#ifdef SK_DEBUG -void GrResourceAllocator::dump() { - unsigned int min = fNumOps+1; - unsigned int max = 0; - for(const Interval* cur = fIntvlList.peekHead(); cur; cur = cur->fNext) { - SkDebugf("{ %d,%d }: [%d, %d]\n", - cur->fProxy->uniqueID().asUInt(), cur->fProxy->underlyingUniqueID().asUInt(), - cur->fStart, cur->fEnd); - if (min > cur->fStart) { - min = cur->fStart; - } - if (max < cur->fEnd) { - max = cur->fEnd; - } - } - - for(const Interval* cur = fIntvlList.peekHead(); cur; cur = cur->fNext) { - SkDebugf("{ %3d,%3d }: ", - cur->fProxy->uniqueID().asUInt(), cur->fProxy->underlyingUniqueID().asUInt()); - for (unsigned int i = min; i <= max; ++i) { - if (i >= cur->fStart && i <= cur->fEnd) { - SkDebugf("x"); - } else { - SkDebugf(" "); - } - } - SkDebugf("\n"); - } -} -#endif - diff --git a/src/gpu/GrResourceAllocator.h b/src/gpu/GrResourceAllocator.h index 3be4836ca9..d7aed0591e 100644 --- a/src/gpu/GrResourceAllocator.h +++ b/src/gpu/GrResourceAllocator.h @@ -54,7 +54,6 @@ public: } void assign(); - SkDEBUGCODE(void dump();) private: class Interval; @@ -72,6 +71,7 @@ private: } static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } + static void OnFree(GrSurface* s) { s->unref(); } }; typedef SkTMultiMap FreePoolMultiMap; @@ -98,12 +98,27 @@ private: fNext = nullptr; } + const GrSurfaceProxy* proxy() const { return fProxy; } + GrSurfaceProxy* proxy() { return fProxy; } + unsigned int start() const { return fStart; } + unsigned int end() const { return fEnd; } + const Interval* next() const { return fNext; } + Interval* next() { return fNext; } + + void setNext(Interval* next) { fNext = next; } + + void extendEnd(unsigned int newEnd) { + SkASSERT(newEnd >= fEnd); + fEnd = newEnd; + } + // for SkTDynamicHash static const uint32_t& GetKey(const Interval& intvl) { return intvl.fProxyID; } static uint32_t Hash(const uint32_t& key) { return key; } + private: GrSurfaceProxy* fProxy; uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key unsigned int fStart; diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index 771196c81c..94245328f1 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -368,6 +368,7 @@ private: } static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } + static void OnFree(GrGpuResource*) { } }; typedef SkTMultiMap ScratchMap; diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp index 24b42f3507..ec503d7066 100644 --- a/src/gpu/GrSurface.cpp +++ b/src/gpu/GrSurface.cpp @@ -9,6 +9,7 @@ #include "GrContext.h" #include "GrOpList.h" #include "GrRenderTarget.h" +#include "GrResourceProvider.h" #include "GrSurfacePriv.h" #include "GrTexture.h" @@ -18,8 +19,12 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) { size_t size; - int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth; - int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight; + int width = useNextPow2 + ? SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(desc.fWidth)) + : desc.fWidth; + int height = useNextPow2 + ? SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(desc.fHeight)) + : desc.fHeight; bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); if (isRenderTarget) { @@ -53,8 +58,12 @@ size_t GrSurface::ComputeSize(GrPixelConfig config, int colorSamplesPerPixel, GrMipMapped mipMapped, bool useNextPow2) { - width = useNextPow2 ? GrNextPow2(width) : width; - height = useNextPow2 ? GrNextPow2(height) : height; + width = useNextPow2 + ? SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(width)) + : width; + height = useNextPow2 + ? SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(height)) + : height; SkASSERT(kUnknown_GrPixelConfig != config); size_t colorSize = (size_t)width * height * GrBytesPerPixel(config); diff --git a/src/gpu/GrSurfaceProxyPriv.h b/src/gpu/GrSurfaceProxyPriv.h index f88c5cdfd9..1f953f401d 100644 --- a/src/gpu/GrSurfaceProxyPriv.h +++ b/src/gpu/GrSurfaceProxyPriv.h @@ -10,6 +10,8 @@ #include "GrSurfaceProxy.h" +#include "GrResourceProvider.h" + /** Class that adds methods to GrSurfaceProxy that are only intended for use internal to Skia. This class is purely a privileged window into GrSurfaceProxy. It should never have additional data members or virtual methods. */ @@ -56,6 +58,10 @@ public: // Assign this proxy the provided GrSurface as its backing surface void assign(sk_sp surface) { fProxy->assign(std::move(surface)); } + bool requiresNoPendingIO() const { + return fProxy->fFlags & GrResourceProvider::kNoPendingIO_Flag; + } + // Don't abuse this call!!!!!!! bool isExact() const { return SkBackingFit::kExact == fProxy->fFit; } diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp index 9a3d15be97..5c4fe3cc06 100644 --- a/src/gpu/GrTextureOpList.cpp +++ b/src/gpu/GrTextureOpList.cpp @@ -124,14 +124,18 @@ bool GrTextureOpList::copySurface(const GrCaps& caps, } void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const { - if (!fRecordedOps.count()) { - return; - } - unsigned int cur = alloc->numOps(); // Add the interval for all the writes to this opList's target - alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1); + if (fRecordedOps.count()) { + alloc->addInterval(fTarget.get(), cur, cur+fRecordedOps.count()-1); + } else { + // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we + // still need to add an interval for the destination so we create a fake op# for + // the missing clear op. + alloc->addInterval(fTarget.get()); + alloc->incOps(); + } auto gather = [ alloc ] (GrSurfaceProxy* p) { alloc->addInterval(p); @@ -140,9 +144,11 @@ void GrTextureOpList::gatherProxyIntervals(GrResourceAllocator* alloc) const { const GrOp* op = fRecordedOps[i].get(); // only diff from the GrRenderTargetOpList version if (op) { op->visitProxies(gather); - - alloc->incOps(); } + + // Even though the op may have been moved we still need to increment the op count to + // keep all the math consistent. + alloc->incOps(); } } diff --git a/src/gpu/effects/GrArithmeticFP.h b/src/gpu/effects/GrArithmeticFP.h index 6e6b6a5cc2..940f1adcf4 100644 --- a/src/gpu/effects/GrArithmeticFP.h +++ b/src/gpu/effects/GrArithmeticFP.h @@ -25,7 +25,7 @@ public: bool enforcePMColor, std::unique_ptr child) { return std::unique_ptr( - new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, child->clone())); + new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, std::move(child))); } GrArithmeticFP(const GrArithmeticFP& src); std::unique_ptr clone() const override; -- cgit v1.2.3