ccpr: Abstract the draws list in a separate class

Bug: skia:
Change-Id: I583c1bdc470e5830d041955d14b164fc00d5d014
Reviewed-on: https://skia-review.googlesource.com/129227
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2018-05-21 09:10:53 -06:00 committed by Skia Commit-Bot
parent bc721ba4be
commit 4bfb50b904
6 changed files with 119 additions and 58 deletions

View File

@ -15,15 +15,13 @@
GrCCDrawPathsOp::GrCCDrawPathsOp(GrCoverageCountingPathRenderer* ccpr, GrPaint&& paint,
const SkIRect& clipIBounds, const SkMatrix& viewMatrix,
const SkPath& path, const SkRect& devBounds)
: INHERITED(ClassID())
: GrDrawOp(ClassID())
, fCCPR(ccpr)
, fHeadDraw{clipIBounds, viewMatrix, path, paint.getColor(), nullptr}
, fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint))
, fDraws({clipIBounds, viewMatrix, path, paint.getColor(), nullptr})
, fProcessors(std::move(paint)) {
SkDEBUGCODE(fCCPR->incrDrawOpCount_debugOnly());
SkDEBUGCODE(fBaseInstance = -1);
SkDEBUGCODE(fInstanceCount = 1);
SkDEBUGCODE(fNumSkippedInstances = 0);
// FIXME: intersect with clip bounds to (hopefully) improve batching.
// (This is nontrivial due to assumptions in generating the octagon cover geometry.)
this->setBounds(devBounds, GrOp::HasAABloat::kYes, GrOp::IsZeroArea::kNo);
@ -42,11 +40,10 @@ GrDrawOp::RequiresDstTexture GrCCDrawPathsOp::finalize(const GrCaps& caps,
GrPixelConfigIsClamped dstIsClamped) {
SkASSERT(!fCCPR->isFlushing_debugOnly());
// There should only be one single path draw in this Op right now.
SkASSERT(1 == fInstanceCount);
SkASSERT(&fHeadDraw == fTailDraw);
SkASSERT(1 == fNumDraws);
GrProcessorSet::Analysis analysis =
fProcessors.finalize(fHeadDraw.fColor, GrProcessorAnalysisCoverage::kSingleChannel,
clip, false, caps, dstIsClamped, &fHeadDraw.fColor);
fProcessors.finalize(fDraws.head().fColor, GrProcessorAnalysisCoverage::kSingleChannel,
clip, false, caps, dstIsClamped, &fDraws.head().fColor);
return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
}
@ -55,22 +52,20 @@ bool GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps& caps) {
SkASSERT(fCCPR == that->fCCPR);
SkASSERT(!fCCPR->isFlushing_debugOnly());
SkASSERT(fOwningRTPendingPaths);
SkASSERT(fInstanceCount);
SkASSERT(fNumDraws);
SkASSERT(!that->fOwningRTPendingPaths || that->fOwningRTPendingPaths == fOwningRTPendingPaths);
SkASSERT(that->fInstanceCount);
SkASSERT(that->fNumDraws);
if (this->getFillType() != that->getFillType() || fSRGBFlags != that->fSRGBFlags ||
fProcessors != that->fProcessors) {
return false;
}
fTailDraw->fNext = &fOwningRTPendingPaths->fDrawsAllocator.push_back(that->fHeadDraw);
fTailDraw = (that->fTailDraw == &that->fHeadDraw) ? fTailDraw->fNext : that->fTailDraw;
fDraws.append(std::move(that->fDraws), &fOwningRTPendingPaths->fAllocator);
this->joinBounds(*that);
SkDEBUGCODE(fInstanceCount += that->fInstanceCount);
SkDEBUGCODE(that->fInstanceCount = 0);
SkDEBUGCODE(fNumDraws += that->fNumDraws);
SkDEBUGCODE(that->fNumDraws = 0);
return true;
}
@ -80,21 +75,30 @@ void GrCCDrawPathsOp::wasRecorded(GrRenderTargetOpList* opList) {
fOwningRTPendingPaths->fDrawOps.addToTail(this);
}
int GrCCDrawPathsOp::countPaths(GrCCPathParser::PathStats* stats) const {
int numPaths = 0;
for (const GrCCDrawPathsOp::SingleDraw& draw : fDraws) {
stats->statPath(draw.fPath);
++numPaths;
}
return numPaths;
}
void GrCCDrawPathsOp::setupResources(GrCCPerFlushResources* resources,
GrOnFlushResourceProvider* onFlushRP) {
const GrCCAtlas* currentAtlas = nullptr;
SkASSERT(fInstanceCount > 0);
SkASSERT(fNumDraws > 0);
SkASSERT(-1 == fBaseInstance);
fBaseInstance = resources->pathInstanceCount();
for (const SingleDraw* draw = this->head(); draw; draw = draw->fNext) {
for (const SingleDraw& draw : fDraws) {
// addPathToAtlas gives us two tight bounding boxes: one in device space, as well as a
// second one rotated an additional 45 degrees. The path vertex shader uses these two
// bounding boxes to generate an octagon that circumscribes the path.
SkRect devBounds, devBounds45;
int16_t atlasOffsetX, atlasOffsetY;
GrCCAtlas* atlas = resources->addPathToAtlas(*onFlushRP->caps(), draw->fClipIBounds,
draw->fMatrix, draw->fPath, &devBounds,
GrCCAtlas* atlas = resources->addPathToAtlas(*onFlushRP->caps(), draw.fClipIBounds,
draw.fMatrix, draw.fPath, &devBounds,
&devBounds45, &atlasOffsetX, &atlasOffsetY);
if (!atlas) {
SkDEBUGCODE(++fNumSkippedInstances);
@ -107,18 +111,17 @@ void GrCCDrawPathsOp::setupResources(GrCCPerFlushResources* resources,
currentAtlas = atlas;
}
const SkMatrix& m = draw->fMatrix;
const SkMatrix& m = draw.fMatrix;
resources->appendDrawPathInstance(
devBounds,
devBounds45,
{{m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY()}},
{{m.getTranslateX(), m.getTranslateY()}},
{{atlasOffsetX, atlasOffsetY}},
draw->fColor);
draw.fColor);
}
SkASSERT(resources->pathInstanceCount() ==
fBaseInstance + fInstanceCount - fNumSkippedInstances);
SkASSERT(resources->pathInstanceCount() == fBaseInstance + fNumDraws - fNumSkippedInstances);
if (currentAtlas) {
this->addAtlasBatch(currentAtlas, resources->pathInstanceCount());
}
@ -157,5 +160,5 @@ void GrCCDrawPathsOp::onExecute(GrOpFlushState* flushState) {
baseInstance, batch.fEndInstanceIdx, this->bounds());
}
SkASSERT(baseInstance == fBaseInstance + fInstanceCount - fNumSkippedInstances);
SkASSERT(baseInstance == fBaseInstance + fNumDraws - fNumSkippedInstances);
}

View File

@ -9,7 +9,9 @@
#define GrCCDrawPathsOp_DEFINED
#include "SkTInternalLList.h"
#include "ccpr/GrCCPathParser.h"
#include "ccpr/GrCCPathProcessor.h"
#include "ccpr/GrCCSTLList.h"
#include "ops/GrDrawOp.h"
class GrCCAtlas;
@ -29,21 +31,6 @@ public:
const SkMatrix&, const SkPath&, const SkRect& devBounds);
~GrCCDrawPathsOp() override;
struct SingleDraw {
SkIRect fClipIBounds;
SkMatrix fMatrix;
SkPath fPath;
GrColor fColor;
SingleDraw* fNext;
};
const SingleDraw* head() const {
SkASSERT(fInstanceCount >= 1);
return &fHeadDraw;
}
SkDEBUGCODE(int numSkippedInstances_debugOnly() const { return fNumSkippedInstances; })
const char* name() const override { return "GrCCDrawOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
@ -55,14 +42,16 @@ public:
}
void onPrepare(GrOpFlushState*) override {}
int countPaths(GrCCPathParser::PathStats*) const;
void setupResources(GrCCPerFlushResources*, GrOnFlushResourceProvider*);
SkDEBUGCODE(int numSkippedInstances_debugOnly() const { return fNumSkippedInstances; })
void onExecute(GrOpFlushState*) override;
private:
SkPath::FillType getFillType() const {
SkASSERT(fInstanceCount >= 1);
return fHeadDraw.fPath.getFillType();
SkASSERT(fNumDraws >= 1);
return fDraws.head().fPath.getFillType();
}
struct AtlasBatch {
@ -78,20 +67,25 @@ private:
}
GrCoverageCountingPathRenderer* const fCCPR;
const uint32_t fSRGBFlags;
struct SingleDraw {
SkIRect fClipIBounds;
SkMatrix fMatrix;
SkPath fPath;
GrColor fColor;
SingleDraw* fNext;
};
GrCCSTLList<SingleDraw> fDraws;
SkDEBUGCODE(int fNumDraws = 1);
GrProcessorSet fProcessors;
GrCCRTPendingPaths* fOwningRTPendingPaths = nullptr;
SingleDraw fHeadDraw;
SingleDraw* fTailDraw = &fHeadDraw;
const uint32_t fSRGBFlags;
GrProcessorSet fProcessors;
int fBaseInstance;
SkDEBUGCODE(int fInstanceCount);
SkDEBUGCODE(int fNumSkippedInstances);
SkSTArray<1, AtlasBatch, true> fAtlasBatches;
typedef GrDrawOp INHERITED;
SkDEBUGCODE(int fNumSkippedInstances = 0);
};
#endif

View File

@ -0,0 +1,61 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrCCSTLList_DEFINED
#define GrCCSTLList_DEFINED
#include "SkArenaAlloc.h"
/**
* A singly-linked list whose head element is a local class member. This is required by
* GrCCDrawPathsOp because the owning opList is unknown at the time of creation, so we can't use its
* associated allocator to create the first element.
*/
template<typename T> class GrCCSTLList {
public:
GrCCSTLList(T&& head) : fHead(std::move(head)) {}
~GrCCSTLList() {
T* draw = fHead.fNext; // fHead will be destructed automatically.
while (draw) {
T* next = draw->fNext;
draw->~T();
draw = next;
}
}
const T& head() const { return fHead; }
T& head() { return fHead; }
void append(GrCCSTLList&& right, SkArenaAlloc* alloc) {
T* nextTail = (&right.fHead == right.fTail) ? nullptr : right.fTail;
T* newRightHead =
new (alloc->makeBytesAlignedTo(sizeof(T), alignof(T))) T(std::move(right.fHead));
// Finish the move of right.fHead.
right.fHead.fNext = nullptr;
right.fTail = &right.fHead;
fTail->fNext = newRightHead;
fTail = !nextTail ? newRightHead : nextTail;
}
struct Iter {
bool operator!=(const Iter& that) { return fCurr != that.fCurr; }
const T& operator*() { return *fCurr; }
void operator++() { fCurr = fCurr->fNext; }
const T* fCurr;
};
Iter begin() const { return Iter{&fHead}; }
Iter end() const { return Iter{nullptr}; }
private:
T fHead;
T* fTail = &fHead;
};
#endif

View File

@ -180,12 +180,8 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush
const GrCCRTPendingPaths& rtPendingPaths = iter->second;
for (const GrCCDrawPathsOp* op : rtPendingPaths.fDrawOps) {
for (const GrCCDrawPathsOp::SingleDraw* draw = op->head(); draw; draw = draw->fNext) {
flushingPathStats.statPath(draw->fPath);
++numPathDraws;
}
numPathDraws += op->countPaths(&flushingPathStats);
}
for (const auto& clipsIter : rtPendingPaths.fClipPaths) {
flushingPathStats.statPath(clipsIter.second.deviceSpacePath());
}
@ -213,7 +209,6 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush
op->setupResources(resources.get(), onFlushRP);
SkDEBUGCODE(numSkippedPaths += op->numSkippedInstances_debugOnly());
}
for (auto& clipsIter : rtPendingPaths->fClipPaths) {
clipsIter.second.placePathInAtlas(resources.get(), onFlushRP);
}

View File

@ -10,6 +10,7 @@
#include "GrPathRenderer.h"
#include "GrRenderTargetOpList.h"
#include "SkArenaAlloc.h"
#include "SkTInternalLList.h"
#include "ccpr/GrCCClipPath.h"
#include "ccpr/GrCCDrawPathsOp.h"
@ -34,7 +35,7 @@ struct GrCCRTPendingPaths {
SkTInternalLList<GrCCDrawPathsOp> fDrawOps;
std::map<uint32_t, GrCCClipPath> fClipPaths;
GrSTAllocator<256, GrCCDrawPathsOp::SingleDraw> fDrawsAllocator;
SkSTArenaAlloc<10 * 1024> fAllocator{10 * 1024 * 2};
};
/**

View File

@ -175,6 +175,13 @@ class GrCCPRTest_cleanup : public CCPRTest {
// Ensure paths get unreffed.
for (int i = 0; i < 10; ++i) {
ccpr.drawPath(fPath);
}
REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
ccpr.flush();
REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
// Ensure clip paths get unreffed.
for (int i = 0; i < 10; ++i) {
ccpr.clipFullscreenRect(fPath);
}
REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));