diff options
-rw-r--r-- | include/private/GrSurfaceProxy.h | 1 | ||||
-rw-r--r-- | src/core/SkBlurImageFilter.cpp | 2 | ||||
-rw-r--r-- | src/core/SkTMultiMap.h | 51 | ||||
-rw-r--r-- | src/gpu/GrDrawingManager.cpp | 12 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.cpp | 20 | ||||
-rw-r--r-- | src/gpu/GrResourceAllocator.cpp | 119 | ||||
-rw-r--r-- | src/gpu/GrResourceAllocator.h | 17 | ||||
-rw-r--r-- | src/gpu/GrResourceCache.h | 1 | ||||
-rw-r--r-- | src/gpu/GrSurface.cpp | 17 | ||||
-rw-r--r-- | src/gpu/GrSurfaceProxyPriv.h | 6 | ||||
-rw-r--r-- | src/gpu/GrTextureOpList.cpp | 20 |
11 files changed, 167 insertions, 99 deletions
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h index 0eccdce32c..23f62195c2 100644 --- a/include/private/GrSurfaceProxy.h +++ b/include/private/GrSurfaceProxy.h @@ -130,6 +130,7 @@ protected: void transferRefs() { SkASSERT(fTarget); + SkASSERT(fTarget->fRefCnt > 0); fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref fTarget->fPendingReads += fPendingReads; fTarget->fPendingWrites += fPendingWrites; diff --git a/src/core/SkBlurImageFilter.cpp b/src/core/SkBlurImageFilter.cpp index bb2da09976..2f0759cfd5 100644 --- a/src/core/SkBlurImageFilter.cpp +++ b/src/core/SkBlurImageFilter.cpp @@ -578,7 +578,7 @@ sk_sp<SkSpecialImage> SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* sourc result = this->gpuFilter(source, sigma, input, inputBounds, dstBounds, ctx.outputProperties()); } else - #endif +#endif { // If both sigmas will result in a zero width window, there is nothing to do. if (sigma.x() < kZeroWindow && sigma.y() < kZeroWindow) { diff --git a/src/core/SkTMultiMap.h b/src/core/SkTMultiMap.h index 3d6e38e454..987a306661 100644 --- a/src/core/SkTMultiMap.h +++ b/src/core/SkTMultiMap.h @@ -34,6 +34,7 @@ public: for ( ; !iter.done(); ++iter) { ValueList* next; for (ValueList* cur = &(*iter); cur; cur = next) { + HashTraits::OnFree(cur->fValue); next = cur->fNext; delete cur; } @@ -69,20 +70,7 @@ public: list = list->fNext; } - if (list->fNext) { - ValueList* next = list->fNext; - list->fValue = next->fValue; - list->fNext = next->fNext; - delete next; - } else if (prev) { - prev->fNext = nullptr; - delete list; - } else { - fHash.remove(key); - delete list; - } - - --fCount; + this->internalRemove(prev, list, key); } T* find(const Key& key) const { @@ -105,6 +93,23 @@ public: return nullptr; } + template<class FindPredicate> + T* findAndRemove(const Key& key, const FindPredicate f) { + ValueList* list = fHash.find(key); + + ValueList* prev = nullptr; + while (list) { + if (f(list->fValue)){ + T* value = list->fValue; + this->internalRemove(prev, list, key); + return value; + } + prev = list; + list = list->fNext; + } + return nullptr; + } + int count() const { return fCount; } #ifdef SK_DEBUG @@ -168,6 +173,24 @@ public: private: SkTDynamicHash<ValueList, Key> fHash; int fCount; + + void internalRemove(ValueList* prev, ValueList* elem, const Key& key) { + if (elem->fNext) { + ValueList* next = elem->fNext; + elem->fValue = next->fValue; + elem->fNext = next->fNext; + delete next; + } else if (prev) { + prev->fNext = nullptr; + delete elem; + } else { + fHash.remove(key); + delete elem; + } + + --fCount; + } + }; #endif 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<Interval>(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<GrSurface> 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<GrSurface> 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<GrSurface> 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<GrSurface> surface = this->findSurfaceFor(cur->fProxy); + sk_sp<GrSurface> 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<GrSurface, GrScratchKey, FreePoolTraits> 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<GrGpuResource, GrScratchKey, ScratchMapTraits> 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<GrSurface> 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(); } } |