diff --git a/src/gpu/ccpr/GrCCGeometry.h b/src/gpu/ccpr/GrCCGeometry.h index 571b3c0a52..5c5d1d2672 100644 --- a/src/gpu/ccpr/GrCCGeometry.h +++ b/src/gpu/ccpr/GrCCGeometry.h @@ -49,9 +49,10 @@ public: bool operator==(const PrimitiveTallies&); }; - GrCCGeometry(int numSkPoints = 0, int numSkVerbs = 0) + GrCCGeometry(int numSkPoints = 0, int numSkVerbs = 0, int numConicWeights = 0) : fPoints(numSkPoints * 3) // Reserve for a 3x expansion in points and verbs. - , fVerbs(numSkVerbs * 3) {} + , fVerbs(numSkVerbs * 3) + , fConicWeights(numConicWeights * 3/2) {} const SkTArray& points() const { SkASSERT(!fBuildingContour); return fPoints; } const SkTArray& verbs() const { SkASSERT(!fBuildingContour); return fVerbs; } @@ -124,8 +125,8 @@ private: SkDEBUGCODE(bool fBuildingContour = false); SkSTArray<128, SkPoint, true> fPoints; - SkSTArray<32, float, true> fConicWeights; SkSTArray<128, Verb, true> fVerbs; + SkSTArray<32, float, true> fConicWeights; }; inline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b) { diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp index 1629a191a5..b29bec7cb1 100644 --- a/src/gpu/ccpr/GrCCPathParser.cpp +++ b/src/gpu/ccpr/GrCCPathParser.cpp @@ -21,13 +21,13 @@ using TriPointInstance = GrCCCoverageProcessor::TriPointInstance; using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance; -GrCCPathParser::GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, - int numSkVerbs) - : fLocalDevPtsBuffer(maxPathPoints + 1) // Overallocate by one point to accomodate for - // overflow with Sk4f. (See parsePath.) - , fGeometry(numSkPoints, numSkVerbs) - , fPathsInfo(maxTotalPaths) - , fScissorSubBatches(maxTotalPaths) +GrCCPathParser::GrCCPathParser(int numPaths, const PathStats& pathStats) + // Overallocate by one point to accomodate for overflow with Sk4f. (See parsePath.) + : fLocalDevPtsBuffer(pathStats.fMaxPointsPerPath + 1) + , fGeometry(pathStats.fNumTotalSkPoints, pathStats.fNumTotalSkVerbs, + pathStats.fNumTotalConicWeights) + , fPathsInfo(numPaths) + , fScissorSubBatches(numPaths) , fTotalPrimitiveCounts{PrimitiveTallies(), PrimitiveTallies()} { // Batches decide what to draw by looking where the previous one ended. Define initial batches // that "end" at the beginning of the data. These will not be drawn, but will only be be read by diff --git a/src/gpu/ccpr/GrCCPathParser.h b/src/gpu/ccpr/GrCCPathParser.h index 973c873f2b..b48a0b8adf 100644 --- a/src/gpu/ccpr/GrCCPathParser.h +++ b/src/gpu/ccpr/GrCCPathParser.h @@ -10,9 +10,11 @@ #include "GrMesh.h" #include "GrNonAtomicRef.h" -#include "GrTessellator.h" +#include "SkPath.h" +#include "SkPathPriv.h" #include "SkRect.h" #include "SkRefCnt.h" +#include "GrTessellator.h" #include "ccpr/GrCCCoverageProcessor.h" #include "ccpr/GrCCGeometry.h" #include "ops/GrDrawOp.h" @@ -32,7 +34,16 @@ public: enum class ScissorMode : int { kNonScissored = 0, kScissored = 1 }; static constexpr int kNumScissorModes = 2; - GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, int numSkVerbs); + struct PathStats { + int fMaxPointsPerPath = 0; + int fNumTotalSkPoints = 0; + int fNumTotalSkVerbs = 0; + int fNumTotalConicWeights = 0; + + void statPath(const SkPath&); + }; + + GrCCPathParser(int numPaths, const PathStats&); ~GrCCPathParser() { // Enforce the contract that the client always calls saveParsedPath or discardParsedPath. @@ -151,4 +162,11 @@ private: mutable SkSTArray<32, GrPipeline::DynamicState> fDynamicStatesScratchBuffer; }; +inline void GrCCPathParser::PathStats::statPath(const SkPath& path) { + fMaxPointsPerPath = SkTMax(fMaxPointsPerPath, path.countPoints()); + fNumTotalSkPoints += path.countPoints(); + fNumTotalSkVerbs += path.countVerbs(); + fNumTotalConicWeights += SkPathPriv::ConicWeightCnt(path); +} + #endif diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index 26348964ea..6c2c00b91b 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -254,6 +254,7 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush using PathInstance = GrCCPathProcessor::Instance; SkASSERT(!fFlushing); + SkASSERT(fFlushingRTPathIters.empty()); SkASSERT(!fPerFlushIndexBuffer); SkASSERT(!fPerFlushVertexBuffer); SkASSERT(!fPerFlushInstanceBuffer); @@ -267,40 +268,38 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush fPerFlushResourcesAreValid = false; - // Count the paths that are being flushed. - int maxTotalPaths = 0, maxPathPoints = 0, numSkPoints = 0, numSkVerbs = 0; - SkDEBUGCODE(int numClipPaths = 0); + // Count up the paths about to be flushed so we can preallocate buffers. + int numPathDraws = 0; + int numClipPaths = 0; + GrCCPathParser::PathStats flushingPathStats; + fFlushingRTPathIters.reserve(numOpListIDs); for (int i = 0; i < numOpListIDs; ++i) { - auto it = fRTPendingPathsMap.find(opListIDs[i]); - if (fRTPendingPathsMap.end() == it) { + auto iter = fRTPendingPathsMap.find(opListIDs[i]); + if (fRTPendingPathsMap.end() == iter) { continue; } - const RTPendingPaths& rtPendingPaths = it->second; + const RTPendingPaths& rtPendingPaths = iter->second; SkTInternalLList::Iter drawOpsIter; drawOpsIter.init(rtPendingPaths.fDrawOps, SkTInternalLList::Iter::kHead_IterStart); while (DrawPathsOp* op = drawOpsIter.get()) { for (const DrawPathsOp::SingleDraw* draw = op->head(); draw; draw = draw->fNext) { - ++maxTotalPaths; - maxPathPoints = SkTMax(draw->fPath.countPoints(), maxPathPoints); - numSkPoints += draw->fPath.countPoints(); - numSkVerbs += draw->fPath.countVerbs(); + ++numPathDraws; + flushingPathStats.statPath(draw->fPath); } drawOpsIter.next(); } - maxTotalPaths += rtPendingPaths.fClipPaths.size(); - SkDEBUGCODE(numClipPaths += rtPendingPaths.fClipPaths.size()); + numClipPaths += rtPendingPaths.fClipPaths.size(); for (const auto& clipsIter : rtPendingPaths.fClipPaths) { - const SkPath& path = clipsIter.second.deviceSpacePath(); - maxPathPoints = SkTMax(path.countPoints(), maxPathPoints); - numSkPoints += path.countPoints(); - numSkVerbs += path.countVerbs(); + flushingPathStats.statPath(clipsIter.second.deviceSpacePath()); } + + fFlushingRTPathIters.push_back(std::move(iter)); } - if (!maxTotalPaths) { + if (0 == numPathDraws + numClipPaths) { return; // Nothing to draw. } @@ -318,7 +317,7 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush } fPerFlushInstanceBuffer = - onFlushRP->makeBuffer(kVertex_GrBufferType, maxTotalPaths * sizeof(PathInstance)); + onFlushRP->makeBuffer(kVertex_GrBufferType, numPathDraws * sizeof(PathInstance)); if (!fPerFlushInstanceBuffer) { SkDebugf("WARNING: failed to allocate path instance buffer. No paths will be drawn.\n"); return; @@ -328,35 +327,31 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush SkASSERT(pathInstanceData); int pathInstanceIdx = 0; - fPerFlushPathParser = sk_make_sp(maxTotalPaths, maxPathPoints, numSkPoints, - numSkVerbs); - SkDEBUGCODE(int skippedTotalPaths = 0); + fPerFlushPathParser = sk_make_sp(numPathDraws + numClipPaths, + flushingPathStats); + SkDEBUGCODE(int numSkippedPaths = 0); // Allocate atlas(es) and fill out GPU instance buffers. - for (int i = 0; i < numOpListIDs; ++i) { - auto it = fRTPendingPathsMap.find(opListIDs[i]); - if (fRTPendingPathsMap.end() == it) { - continue; - } - RTPendingPaths& rtPendingPaths = it->second; + for (const auto& iter : fFlushingRTPathIters) { + RTPendingPaths* rtPendingPaths = &iter->second; SkTInternalLList::Iter drawOpsIter; - drawOpsIter.init(rtPendingPaths.fDrawOps, + drawOpsIter.init(rtPendingPaths->fDrawOps, SkTInternalLList::Iter::kHead_IterStart); while (DrawPathsOp* op = drawOpsIter.get()) { pathInstanceIdx = op->setupResources(onFlushRP, pathInstanceData, pathInstanceIdx); drawOpsIter.next(); - SkDEBUGCODE(skippedTotalPaths += op->numSkippedInstances_debugOnly()); + SkDEBUGCODE(numSkippedPaths += op->numSkippedInstances_debugOnly()); } - for (auto& clipsIter : rtPendingPaths.fClipPaths) { + for (auto& clipsIter : rtPendingPaths->fClipPaths) { clipsIter.second.placePathInAtlas(this, onFlushRP, fPerFlushPathParser.get()); } } fPerFlushInstanceBuffer->unmap(); - SkASSERT(pathInstanceIdx == maxTotalPaths - skippedTotalPaths - numClipPaths); + SkASSERT(pathInstanceIdx == numPathDraws - numSkippedPaths); if (!fPerFlushAtlases.empty()) { auto coverageCountBatchID = fPerFlushPathParser->closeCurrentBatch(); @@ -528,8 +523,9 @@ void GrCoverageCountingPathRenderer::postFlush(GrDeferredUploadToken, const uint fPerFlushVertexBuffer.reset(); fPerFlushIndexBuffer.reset(); // We wait to erase these until after flush, once Ops and FPs are done accessing their data. - for (int i = 0; i < numOpListIDs; ++i) { - fRTPendingPathsMap.erase(opListIDs[i]); + for (const auto& iter : fFlushingRTPathIters) { + fRTPendingPathsMap.erase(iter); } + fFlushingRTPathIters.reset(); SkDEBUGCODE(fFlushing = false); } diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h index da3c2e7086..0e9ed7b8b1 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h @@ -220,6 +220,7 @@ private: // A map from render target ID to the individual render target's pending paths. std::map fRTPendingPathsMap; + SkSTArray<4, std::map::iterator> fFlushingRTPathIters; SkDEBUGCODE(int fPendingDrawOpsCount = 0); sk_sp fPerFlushIndexBuffer;