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:
parent
bc721ba4be
commit
4bfb50b904
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
61
src/gpu/ccpr/GrCCSTLList.h
Normal file
61
src/gpu/ccpr/GrCCSTLList.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user