ccpr: Cleanup on-flush path stats

Adds a wrapper struct to limit the number of free variables. Fixes a
bug where we preallocated draw instances for clip paths. Counts conic
weights and preallocates their buffer as well.

Bug: skia:
Change-Id: I72779c9017322a0dc64461c8cb927f975406b9af
Reviewed-on: https://skia-review.googlesource.com/126844
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2018-05-09 00:40:52 -06:00 committed by Skia Commit-Bot
parent e8f9e913b6
commit 3917b1e9bc
5 changed files with 61 additions and 45 deletions

View File

@ -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<SkPoint, true>& points() const { SkASSERT(!fBuildingContour); return fPoints; }
const SkTArray<Verb, true>& 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) {

View File

@ -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

View File

@ -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

View File

@ -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<DrawPathsOp>::Iter drawOpsIter;
drawOpsIter.init(rtPendingPaths.fDrawOps,
SkTInternalLList<DrawPathsOp>::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<GrCCPathParser>(maxTotalPaths, maxPathPoints, numSkPoints,
numSkVerbs);
SkDEBUGCODE(int skippedTotalPaths = 0);
fPerFlushPathParser = sk_make_sp<GrCCPathParser>(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<DrawPathsOp>::Iter drawOpsIter;
drawOpsIter.init(rtPendingPaths.fDrawOps,
drawOpsIter.init(rtPendingPaths->fDrawOps,
SkTInternalLList<DrawPathsOp>::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);
}

View File

@ -220,6 +220,7 @@ private:
// A map from render target ID to the individual render target's pending paths.
std::map<uint32_t, RTPendingPaths> fRTPendingPathsMap;
SkSTArray<4, std::map<uint32_t, RTPendingPaths>::iterator> fFlushingRTPathIters;
SkDEBUGCODE(int fPendingDrawOpsCount = 0);
sk_sp<const GrBuffer> fPerFlushIndexBuffer;