Replace GrAAType with flags for path renderers

Replaces the single GrAAType with a set of flags indicating which AA
types are acceptable for the path renderer to use.

Bug: skia:
Change-Id: I773565c904a360355e771966b6cddba697e1165f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/200840
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2019-03-13 00:22:01 -06:00 committed by Skia Commit-Bot
parent 93b9451239
commit 09e56897ab
22 changed files with 208 additions and 162 deletions

View File

@ -266,8 +266,8 @@ void WindowRectanglesMaskGM::stencilCheckerboard(GrRenderTargetContext* rtc, boo
for (int x = (y & 1) == flip ? 0 : kMaskCheckerSize;
x < kDeviceRect.width(); x += 2 * kMaskCheckerSize) {
SkIRect checker = SkIRect::MakeXYWH(x, y, kMaskCheckerSize, kMaskCheckerSize);
rtc->priv().stencilRect(GrNoClip(), &kSetClip, GrAAType::kNone, SkMatrix::I(),
SkRect::Make(checker));
rtc->priv().stencilRect(
GrNoClip(), &kSetClip, GrAA::kNo, SkMatrix::I(), SkRect::Make(checker));
}
}
}

View File

@ -114,6 +114,12 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrRecordingContext* context,
path.toggleInverseFillType();
}
// We only use this method when rendering coverage clip masks.
SkASSERT(GrFSAAType::kNone == renderTargetContext->fsaaType());
auto aaTypeFlags = (element->isAA())
? GrPathRenderer::AATypeFlags::kCoverage
: GrPathRenderer::AATypeFlags::kNone;
GrPathRendererChain::DrawType type =
needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor
: GrPathRendererChain::DrawType::kColor;
@ -124,10 +130,7 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrRecordingContext* context,
canDrawArgs.fClipConservativeBounds = &scissorRect;
canDrawArgs.fViewMatrix = &viewMatrix;
canDrawArgs.fShape = &shape;
canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()),
renderTargetContext->fsaaType(),
GrAllowMixedSamples::kYes,
*context->priv().caps());
canDrawArgs.fAATypeFlags = aaTypeFlags;
SkASSERT(!renderTargetContext->wrapsVkSecondaryCB());
canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;

View File

@ -22,7 +22,6 @@ void GrPathRenderer::StencilPathArgs::validate() const {
SkASSERT(fViewMatrix);
SkASSERT(fShape);
SkASSERT(fShape->style().isSimpleFill());
SkASSERT(GrAAType::kCoverage != fAAType);
SkPath path;
fShape->asPath(&path);
SkASSERT(!path.isInverseFillType());
@ -49,15 +48,14 @@ bool GrPathRenderer::drawPath(const DrawPathArgs& args) {
canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
canArgs.fViewMatrix = args.fViewMatrix;
canArgs.fShape = args.fShape;
canArgs.fAAType = args.fAAType;
canArgs.fAATypeFlags = args.fAATypeFlags;
canArgs.fTargetIsWrappedVkSecondaryCB = args.fRenderTargetContext->wrapsVkSecondaryCB();
canArgs.validate();
canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType()));
SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
GrFSAAType::kMixedSamples != args.fRenderTargetContext->fsaaType()));
if (AATypeFlags::kMixedSampledStencilThenCover & canArgs.fAATypeFlags) {
SkASSERT(GrFSAAType::kMixedSamples == args.fRenderTargetContext->fsaaType());
}
SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
if (!args.fUserStencilSettings->isUnused()) {
SkPath path;
@ -118,7 +116,9 @@ void GrPathRenderer::onStencilPath(const StencilPathArgs& args) {
args.fClipConservativeBounds,
args.fViewMatrix,
args.fShape,
args.fAAType,
(GrAA::kYes == args.fDoStencilMSAA)
? AATypeFlags::kMSAA
: AATypeFlags::kNone,
false};
this->drawPath(drawArgs);
}

View File

@ -72,6 +72,17 @@ public:
kYes
};
/**
* This enum defines a set of flags indicating which AA methods would be acceptable for a path
* renderer to employ (if any) while drawing a given path.
*/
enum class AATypeFlags {
kNone = 0,
kCoverage = (1 << 0),
kMSAA = (1 << 1),
kMixedSampledStencilThenCover = (1 << 2),
};
struct CanDrawPathArgs {
SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
@ -79,7 +90,7 @@ public:
const SkIRect* fClipConservativeBounds;
const SkMatrix* fViewMatrix;
const GrShape* fShape;
GrAAType fAAType;
AATypeFlags fAATypeFlags;
bool fTargetIsWrappedVkSecondaryCB;
// This is only used by GrStencilAndCoverPathRenderer
@ -114,7 +125,7 @@ public:
const SkIRect* fClipConservativeBounds;
const SkMatrix* fViewMatrix;
const GrShape* fShape;
GrAAType fAAType;
AATypeFlags fAATypeFlags;
bool fGammaCorrect;
#ifdef SK_DEBUG
void validate() const {
@ -145,8 +156,8 @@ public:
const GrHardClip* fClip;
const SkIRect* fClipConservativeBounds;
const SkMatrix* fViewMatrix;
GrAAType fAAType;
const GrShape* fShape;
GrAA fDoStencilMSAA;
SkDEBUGCODE(void validate() const);
};
@ -202,4 +213,6 @@ private:
typedef SkRefCnt INHERITED;
};
GR_MAKE_BITFIELD_CLASS_OPS(GrPathRenderer::AATypeFlags);
#endif

View File

@ -824,12 +824,13 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
// walk through each clip element and perform its set op with the existing clip.
for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) {
using AATypeFlags = GrPathRenderer::AATypeFlags;
const Element* element = iter.get();
GrAAType aaType = GrAAType::kNone;
if (element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) {
aaType = GrAAType::kMSAA;
}
bool doStencilMSAA =
element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType();
// Since we are only drawing to the stencil buffer, we can use kMSAA even if the render
// target is mixed sampled.
auto pathAATypeFlags = (doStencilMSAA) ? AATypeFlags::kMSAA : AATypeFlags::kNone;
bool fillInverted = false;
// This will be used to determine whether the clip shape can be rendered into the
@ -856,7 +857,7 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
canDrawArgs.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
canDrawArgs.fViewMatrix = &SkMatrix::I();
canDrawArgs.fShape = &shape;
canDrawArgs.fAAType = aaType;
canDrawArgs.fAATypeFlags = pathAATypeFlags;
canDrawArgs.fHasUserStencilSettings = false;
canDrawArgs.fTargetIsWrappedVkSecondaryCB = renderTargetContext->wrapsVkSecondaryCB();
@ -890,9 +891,9 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
0xffff>()
);
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil,
aaType, SkMatrix::I(),
element->getDeviceSpaceRect());
renderTargetContext->priv().stencilRect(
stencilClip.fixedClip(), &kDrawToStencil, GrAA(doStencilMSAA),
SkMatrix::I(), element->getDeviceSpaceRect());
} else {
if (!clipPath.isEmpty()) {
GrShape shape(clipPath, GrStyle::SimpleFill());
@ -908,7 +909,7 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
&stencilClip.fixedClip().scissorRect(),
&SkMatrix::I(),
&shape,
aaType,
pathAATypeFlags,
false};
pr->drawPath(args);
} else {
@ -918,7 +919,7 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
args.fClip = &stencilClip.fixedClip();
args.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
args.fViewMatrix = &SkMatrix::I();
args.fAAType = aaType;
args.fDoStencilMSAA = GrAA(doStencilMSAA);
args.fShape = &shape;
pr->stencilPath(args);
}
@ -931,9 +932,9 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
if (drawDirectToClip) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType,
SkMatrix::I(),
element->getDeviceSpaceRect());
renderTargetContext->priv().stencilRect(
stencilClip, *pass, GrAA(doStencilMSAA), SkMatrix::I(),
element->getDeviceSpaceRect());
} else {
GrShape shape(clipPath, GrStyle::SimpleFill());
GrPaint paint;
@ -946,15 +947,16 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context,
&stencilClip.fixedClip().scissorRect(),
&SkMatrix::I(),
&shape,
aaType,
pathAATypeFlags,
false};
pr->drawPath(args);
}
} else {
// The view matrix is setup to do clip space -> stencil space translation, so
// draw rect in clip space.
renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, SkMatrix::I(),
SkRect::Make(fScissor));
renderTargetContext->priv().stencilRect(
stencilClip, *pass, GrAA(doStencilMSAA), SkMatrix::I(),
SkRect::Make(fScissor));
}
}
}

View File

@ -142,6 +142,29 @@ GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowM
return GrAAType::kNone;
}
static inline GrPathRenderer::AATypeFlags choose_path_aa_type_flags(
GrAA aa, GrFSAAType fsaaType, const GrCaps& caps) {
using AATypeFlags = GrPathRenderer::AATypeFlags;
if (GrAA::kNo == aa) {
// On some devices we cannot disable MSAA if it is enabled so we make the AA type flags
// reflect that.
if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
return AATypeFlags::kMSAA;
}
return AATypeFlags::kNone;
}
switch (fsaaType) {
case GrFSAAType::kNone:
return AATypeFlags::kCoverage;
case GrFSAAType::kMixedSamples:
return AATypeFlags::kCoverage | AATypeFlags::kMixedSampledStencilThenCover;
case GrFSAAType::kUnifiedMSAA:
return AATypeFlags::kMSAA;
}
SK_ABORT("Invalid GrFSAAType.");
return AATypeFlags::kNone;
}
//////////////////////////////////////////////////////////////////////////////
class AutoCheckFlush {
@ -793,7 +816,7 @@ void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool i
}
void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
GrAAType aaType,
GrAA doStencilMSAA,
const SkMatrix& viewMatrix,
const GrPath* path) {
ASSERT_SINGLE_OWNER_PRIV
@ -802,9 +825,6 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
fRenderTargetContext->fContext);
SkASSERT(aaType != GrAAType::kCoverage);
bool useHWAA = GrAATypeIsHW(aaType);
// TODO: extract portions of checkDraw that are relevant to path stenciling.
SkASSERT(path);
SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
@ -824,7 +844,7 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
viewMatrix,
useHWAA,
GrAA::kYes == doStencilMSAA,
path->getFillType(),
appliedClip.hasStencilClip(),
appliedClip.scissorState(),
@ -838,7 +858,7 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
const GrUserStencilSettings* ss,
GrAAType aaType,
GrAA doStencilMSAA,
const SkMatrix& viewMatrix,
const SkRect& rect) {
ASSERT_SINGLE_OWNER_PRIV
@ -847,11 +867,11 @@ void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
fRenderTargetContext->fContext);
SkASSERT(GrAAType::kCoverage != aaType);
AutoCheckFlush acf(fRenderTargetContext->drawingManager());
GrPaint paint;
paint.setXPFactory(GrDisableColorXPFactory::Get());
auto aaType = (GrAA::kYes == doStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix, rect, ss);
fRenderTargetContext->addDrawOp(clip, std::move(op));
@ -1866,7 +1886,8 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
// the src color (either the input alpha or in the frag shader) to implement
// aa. If we have some future driver-mojo path AA that can do the right
// thing WRT to the blend then we'll need some query on the PR.
GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
auto aaTypeFlags = choose_path_aa_type_flags(
aa, fRenderTargetContext->fsaaType(), *fRenderTargetContext->caps());
bool hasUserStencilSettings = !ss->isUnused();
SkIRect clipConservativeBounds;
@ -1879,7 +1900,7 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
canDrawArgs.fViewMatrix = &viewMatrix;
canDrawArgs.fShape = &shape;
canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
canDrawArgs.fAAType = aaType;
canDrawArgs.fAATypeFlags = aaTypeFlags;
SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
@ -1902,7 +1923,7 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
&clipConservativeBounds,
&viewMatrix,
&shape,
aaType,
aaTypeFlags,
fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
pr->drawPath(args);
return true;
@ -1937,13 +1958,8 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
GrShape tempShape;
// NVPR cannot handle hairlines, so this would get picked up by a different stencil and
// cover path renderer (i.e. default path renderer). The hairline renderer produces much
// smoother hairlines than MSAA.
GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
? GrAllowMixedSamples::kNo
: GrAllowMixedSamples::kYes;
GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
auto aaTypeFlags = choose_path_aa_type_flags(aa, this->fsaaType(), *this->caps());
GrPathRenderer::CanDrawPathArgs canDrawArgs;
canDrawArgs.fCaps = this->caps();
canDrawArgs.fViewMatrix = &viewMatrix;
@ -1958,7 +1974,7 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
return;
}
canDrawArgs.fAAType = aaType;
canDrawArgs.fAATypeFlags = aaTypeFlags;
// Try a 1st time without applying any of the style to the geometry (and barring sw)
pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
@ -2003,7 +2019,7 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
&clipConservativeBounds,
&viewMatrix,
canDrawArgs.fShape,
aaType,
aaTypeFlags,
this->colorSpaceInfo().isLinearlyBlended()};
pr->drawPath(args);
}

View File

@ -62,13 +62,12 @@ public:
*/
void absClear(const SkIRect* rect, const SkPMColor4f& color);
void stencilRect(const GrHardClip&,
const GrUserStencilSettings* ss,
GrAAType,
const SkMatrix& viewMatrix,
const SkRect& rect);
void stencilRect(
const GrHardClip&, const GrUserStencilSettings* ss, GrAA doStencilMSAA,
const SkMatrix& viewMatrix, const SkRect& rect);
void stencilPath(const GrHardClip&, GrAAType, const SkMatrix& viewMatrix, const GrPath*);
void stencilPath(
const GrHardClip&, GrAA doStencilMSAA, const SkMatrix& viewMatrix, const GrPath*);
/**
* Draws a rect, either AA or not, and touches the stencil buffer with the user stencil settings
@ -78,7 +77,7 @@ public:
const GrUserStencilSettings*,
SkRegion::Op op,
bool invert,
GrAA,
GrAA doStencilMSAA,
const SkMatrix& viewMatrix,
const SkRect&);
@ -90,7 +89,7 @@ public:
const GrUserStencilSettings*,
SkRegion::Op op,
bool invert,
GrAA,
GrAA doStencilMSAA,
const SkMatrix& viewMatrix,
const SkPath&);

View File

@ -32,7 +32,7 @@ GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// Pass on any style that applies. The caller will apply the style if a suitable renderer is
// not found and try again with the new GrShape.
if (!args.fShape->style().applies() && SkToBool(fProxyProvider) &&
(args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone)) {
((args.fAATypeFlags & AATypeFlags::kCoverage) || args.fAATypeFlags == AATypeFlags::kNone)) {
// This is the fallback renderer for when a path is too complicated for the GPU ones.
return CanDrawPath::kAsBackup;
}
@ -257,7 +257,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
// To prevent overloading the cache with entries during animations we limit the cache of masks
// to cases where the matrix preserves axis alignment.
bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() &&
args.fShape->hasUnstyledKey() && GrAAType::kCoverage == args.fAAType;
args.fShape->hasUnstyledKey() && (AATypeFlags::kCoverage & args.fAATypeFlags);
if (!GetShapeAndClipBounds(args.fRenderTargetContext,
*args.fClip, *args.fShape,
@ -332,7 +332,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
}
if (!proxy) {
SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox;
GrAA aa = GrAAType::kCoverage == args.fAAType ? GrAA::kYes : GrAA::kNo;
GrAA aa = GrAA(SkToBool(AATypeFlags::kCoverage & args.fAATypeFlags));
SkTaskGroup* taskGroup = nullptr;
if (auto direct = args.fContext->priv().asDirectContext()) {

View File

@ -56,7 +56,7 @@ GrCCPerOpListPaths* GrCoverageCountingPathRenderer::lookupPendingPaths(uint32_t
GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath(
const CanDrawPathArgs& args) const {
const GrShape& shape = *args.fShape;
if (GrAAType::kCoverage != args.fAAType || shape.style().hasPathEffect() ||
if (!(AATypeFlags::kCoverage & args.fAATypeFlags) || shape.style().hasPathEffect() ||
args.fViewMatrix->hasPerspective() || shape.inverseFilled()) {
return CanDrawPath::kNo;
}

View File

@ -654,7 +654,7 @@ sk_sp<GrGeometryProcessor> QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
GrPathRenderer::CanDrawPath
GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
(GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
(AATypeFlags::kCoverage & args.fAATypeFlags) && args.fShape->style().isSimpleFill() &&
!args.fShape->inverseFilled() && args.fShape->knownToBeConvex()) {
return CanDrawPath::kYes;
}

View File

@ -713,7 +713,7 @@ static void add_line(const SkPoint p[2],
GrPathRenderer::CanDrawPath
GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
return CanDrawPath::kNo;
}

View File

@ -39,7 +39,7 @@ GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
GrPathRenderer::CanDrawPath
GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
return CanDrawPath::kNo;
}
if (!args.fShape->knownToBeConvex()) {

View File

@ -18,7 +18,7 @@ GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
SkPoint pts[2];
bool inverted;
if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
if (args.fAAType == GrAAType::kMixedSamples) {
if (args.fAATypeFlags == AATypeFlags::kMixedSampledStencilThenCover) {
return CanDrawPath::kNo;
}
// We should never have an inverse dashed case.
@ -35,18 +35,15 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
"GrDashLinePathRenderer::onDrawPath");
GrDashOp::AAMode aaMode = GrDashOp::AAMode::kNone;
switch (args.fAAType) {
case GrAAType::kNone:
break;
case GrAAType::kCoverage:
case GrAAType::kMixedSamples:
aaMode = GrDashOp::AAMode::kCoverage;
break;
case GrAAType::kMSAA:
if (AATypeFlags::kNone != args.fAATypeFlags) {
if (AATypeFlags::kMSAA & args.fAATypeFlags) {
// In this mode we will use aa between dashes but the outer border uses MSAA. Otherwise,
// we can wind up with external edges antialiased and internal edges unantialiased.
aaMode = GrDashOp::AAMode::kCoverageWithMSAA;
break;
} else {
SkASSERT(AATypeFlags::kCoverage & args.fAATypeFlags);
aaMode = GrDashOp::AAMode::kCoverage;
}
}
SkPoint pts[2];
SkAssertResult(args.fShape->asLine(pts, nullptr));

View File

@ -637,15 +637,19 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget
GrPathRenderer::CanDrawPath
GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bool isHairline = IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr);
bool isHairline = IsStrokeHairlineOrEquivalent(
args.fShape->style(), *args.fViewMatrix, nullptr);
// If we aren't a single_pass_shape or hairline, we require stencil buffers.
if (!(single_pass_shape(*args.fShape) || isHairline) &&
(args.fCaps->avoidStencilBuffers() || args.fTargetIsWrappedVkSecondaryCB)) {
return CanDrawPath::kNo;
}
// This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
if (GrAAType::kCoverage == args.fAAType ||
(!args.fShape->style().isSimpleFill() && !isHairline)) {
// If antialiasing is required, we only support MSAA.
if (AATypeFlags::kNone != args.fAATypeFlags && !(AATypeFlags::kMSAA & args.fAATypeFlags)) {
return CanDrawPath::kNo;
}
// This can draw any path with any simple fill style.
if (!args.fShape->style().isSimpleFill() && !isHairline) {
return CanDrawPath::kNo;
}
// This is the fallback renderer for when a path is too complicated for the others to draw.
@ -655,14 +659,13 @@ GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
"GrDefaultPathRenderer::onDrawPath");
return this->internalDrawPath(args.fRenderTargetContext,
std::move(args.fPaint),
args.fAAType,
*args.fUserStencilSettings,
*args.fClip,
*args.fViewMatrix,
*args.fShape,
false);
GrAAType aaType = (AATypeFlags::kNone != args.fAATypeFlags)
? GrAAType::kMSAA
: GrAAType::kNone;
return this->internalDrawPath(
args.fRenderTargetContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
*args.fClip, *args.fViewMatrix, *args.fShape, false);
}
void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
@ -673,9 +676,11 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
GrPaint paint;
paint.setXPFactory(GrDisableColorXPFactory::Get());
this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
*args.fShape, true);
auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
this->internalDrawPath(
args.fRenderTargetContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
*args.fClip, *args.fViewMatrix, *args.fShape, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -25,12 +25,12 @@ static constexpr GrUserStencilSettings kCoverPass{
};
GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
GrPathRendering::FillType fill, GrAAType aaType)
GrPathRendering::FillType fill, GrAA aa)
: INHERITED(classID)
, fViewMatrix(viewMatrix)
, fInputColor(paint.getColor4f())
, fFillType(fill)
, fAAType(aaType)
, fDoAA(GrAA::kYes == aa)
, fProcessorSet(std::move(paint)) {}
#ifdef SK_DEBUG
@ -44,7 +44,7 @@ SkString GrDrawPathOp::dumpInfo() const {
GrPipeline::InitArgs GrDrawPathOpBase::pipelineInitArgs(const GrOpFlushState& state) {
GrPipeline::InitArgs args;
if (GrAATypeIsHW(fAAType)) {
if (fDoAA) {
args.fFlags |= GrPipeline::kHWAntialias_Flag;
}
args.fUserStencil = &kCoverPass;
@ -77,11 +77,11 @@ void init_stencil_pass_settings(const GrOpFlushState& flushState,
std::unique_ptr<GrDrawOp> GrDrawPathOp::Make(GrRecordingContext* context,
const SkMatrix& viewMatrix,
GrPaint&& paint,
GrAAType aaType,
GrAA aa,
GrPath* path) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<GrDrawPathOp>(viewMatrix, std::move(paint), aaType, path);
return pool->allocate<GrDrawPathOp>(viewMatrix, std::move(paint), aa, path);
}
void GrDrawPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {

View File

@ -22,13 +22,12 @@ class GrRecordingContext;
class GrDrawPathOpBase : public GrDrawOp {
protected:
GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&,
GrPathRendering::FillType, GrAAType);
GrPathRendering::FillType, GrAA);
FixedFunctionFlags fixedFunctionFlags() const override {
if (GrAATypeIsHW(fAAType)) {
return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
}
return FixedFunctionFlags::kUsesStencil;
return (fDoAA)
? FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil
: FixedFunctionFlags::kUsesStencil;
}
GrProcessorSet::Analysis finalize(
const GrCaps& caps, const GrAppliedClip* clip, GrFSAAType fsaaType) override {
@ -60,7 +59,7 @@ private:
SkPMColor4f fInputColor;
GrProcessorSet::Analysis fAnalysis;
GrPathRendering::FillType fFillType;
GrAAType fAAType;
bool fDoAA;
GrProcessorSet fProcessorSet;
typedef GrDrawOp INHERITED;
@ -70,11 +69,8 @@ class GrDrawPathOp final : public GrDrawPathOpBase {
public:
DEFINE_OP_CLASS_ID
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext*,
const SkMatrix& viewMatrix,
GrPaint&&,
GrAAType,
GrPath*);
static std::unique_ptr<GrDrawOp> Make(
GrRecordingContext*, const SkMatrix& viewMatrix, GrPaint&&, GrAA, GrPath*);
const char* name() const override { return "DrawPath"; }
@ -85,8 +81,9 @@ public:
private:
friend class GrOpMemoryPool; // for ctor
GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAAType aaType, const GrPath* path)
: GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aaType)
GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, const GrPath* path)
: GrDrawPathOpBase(
ClassID(), viewMatrix, std::move(paint), path->getFillType(), aa)
, fPath(path) {
this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}

View File

@ -188,7 +188,7 @@ GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPath
return CanDrawPath::kNo;
}
// This does non-inverse coverage-based antialiased fills.
if (GrAAType::kCoverage != args.fAAType) {
if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
return CanDrawPath::kNo;
}
// TODO: Support inverse fill

View File

@ -46,7 +46,7 @@ GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const
return CanDrawPath::kNo;
}
// doesn't do per-path AA, relies on the target having MSAA.
if (GrAAType::kCoverage == args.fAAType) {
if (AATypeFlags::kCoverage == args.fAATypeFlags) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
@ -81,8 +81,8 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
"GrStencilAndCoverPathRenderer::onStencilPath");
sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
*args.fViewMatrix, p.get());
args.fRenderTargetContext->priv().stencilPath(
*args.fClip, args.fDoStencilMSAA, *args.fViewMatrix, p.get());
}
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
@ -92,6 +92,9 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
const SkMatrix& viewMatrix = *args.fViewMatrix;
bool doStencilMSAA = AATypeFlags::kNone != args.fAATypeFlags;
SkASSERT(!doStencilMSAA ||
(AATypeFlags::kMSAA | AATypeFlags::kMixedSampledStencilThenCover) & args.fAATypeFlags);
sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
@ -106,8 +109,9 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
// fake inverse with a stencil and cover
GrAppliedClip appliedClip;
if (!args.fClip->apply(args.fContext, args.fRenderTargetContext,
GrAATypeIsHW(args.fAAType), true, &appliedClip, &devBounds)) {
if (!args.fClip->apply(
args.fContext, args.fRenderTargetContext, doStencilMSAA, true, &appliedClip,
&devBounds)) {
return true;
}
GrStencilClip stencilClip(appliedClip.stencilStackID());
@ -120,8 +124,8 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
}
// Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the
// final draw and it is meaningless to multiply by coverage when drawing to stencil.
args.fRenderTargetContext->priv().stencilPath(stencilClip, args.fAAType, viewMatrix,
path.get());
args.fRenderTargetContext->priv().stencilPath(
stencilClip, GrAA(doStencilMSAA), viewMatrix, path.get());
{
static constexpr GrUserStencilSettings kInvertedCoverPass(
@ -153,23 +157,22 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
// We have to suppress enabling MSAA for mixed samples or we will get seams due to
// coverage modulation along the edge where two triangles making up the rect meet.
GrAAType coverAAType = args.fAAType;
if (GrAAType::kMixedSamples == coverAAType) {
coverAAType = GrAAType::kNone;
GrAAType coverAAType = GrAAType::kNone;
if (AATypeFlags::kMSAA & args.fAATypeFlags) {
SkASSERT(!(AATypeFlags::kMixedSampledStencilThenCover & args.fAATypeFlags));
coverAAType = GrAAType::kMSAA;
}
// This is a non-coverage aa rect operation
SkASSERT(coverAAType == GrAAType::kNone || coverAAType == GrAAType::kMSAA);
std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
args.fContext, std::move(args.fPaint),
coverAAType, coverMatrix, localMatrix,
coverBounds, &kInvertedCoverPass);
args.fContext, std::move(args.fPaint), coverAAType, coverMatrix, localMatrix,
coverBounds, &kInvertedCoverPass);
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
}
} else {
std::unique_ptr<GrDrawOp> op =
GrDrawPathOp::Make(args.fContext, viewMatrix, std::move(args.fPaint),
args.fAAType, path.get());
std::unique_ptr<GrDrawOp> op = GrDrawPathOp::Make(
args.fContext, viewMatrix, std::move(args.fPaint), GrAA(doStencilMSAA), path.get());
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
}

View File

@ -145,21 +145,25 @@ GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// This path renderer can draw fill styles, and can do screenspace antialiasing via a
// one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
// ones to simpler algorithms. We pass on paths that have styles, though they may come back
// around after applying the styling information to the geometry to create a filled path. In
// the non-AA case, We skip paths that don't have a key since the real advantage of this path
// renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
// accept paths without keys.
// around after applying the styling information to the geometry to create a filled path.
if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
return CanDrawPath::kNo;
}
if (GrAAType::kCoverage == args.fAAType) {
if (AATypeFlags::kNone == args.fAATypeFlags || (AATypeFlags::kMSAA & args.fAATypeFlags)) {
// Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that don't
// have a key since the real advantage of this path renderer comes from caching the
// tessellated geometry.
if (!args.fShape->hasUnstyledKey()) {
return CanDrawPath::kNo;
}
} else if (AATypeFlags::kCoverage & args.fAATypeFlags) {
// Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept paths
// without keys.
SkPath path;
args.fShape->asPath(&path);
if (path.countVerbs() > GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
return CanDrawPath::kNo;
}
} else if (!args.fShape->hasUnstyledKey()) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
}
@ -390,13 +394,15 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
args.fRenderTargetContext->height(),
&clipBoundsI);
std::unique_ptr<GrDrawOp> op = TessellatingPathOp::Make(args.fContext,
std::move(args.fPaint),
*args.fShape,
*args.fViewMatrix,
clipBoundsI,
args.fAAType,
args.fUserStencilSettings);
GrAAType aaType = GrAAType::kNone;
if (AATypeFlags::kMSAA & args.fAATypeFlags) {
aaType = GrAAType::kMSAA;
} else if (AATypeFlags::kCoverage & args.fAATypeFlags) {
aaType = GrAAType::kCoverage;
}
std::unique_ptr<GrDrawOp> op = TessellatingPathOp::Make(
args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, clipBoundsI,
aaType, args.fUserStencilSettings);
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
return true;
}

View File

@ -112,7 +112,7 @@ public:
fCCPR->testingOnly_drawPathDirectly({
fCtx.get(), std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(), &noClip,
&clipBounds, &matrix, &shape, GrAAType::kCoverage, false});
&clipBounds, &matrix, &shape, GrPathRenderer::AATypeFlags::kCoverage, false});
}
void clipFullscreenRect(SkPath clipPath, SkPMColor4f color = { 0, 1, 0, 1 }) {

View File

@ -28,11 +28,13 @@ static SkPath create_concave_path() {
return path;
}
using AATypeFlags = GrPathRenderer::AATypeFlags;
static void draw_path(GrContext* ctx,
GrRenderTargetContext* renderTargetContext,
const SkPath& path,
GrPathRenderer* pr,
GrAAType aaType,
AATypeFlags aaTypeFlags,
const GrStyle& style) {
GrPaint paint;
paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
@ -53,7 +55,7 @@ static void draw_path(GrContext* ctx,
&clipConservativeBounds,
&matrix,
&shape,
aaType,
aaTypeFlags,
false};
pr->drawPath(args);
}
@ -72,7 +74,7 @@ static void test_path(skiatest::Reporter* reporter,
std::function<SkPath(void)> createPath,
std::function<GrPathRenderer*(GrContext*)> createPathRenderer,
int expected,
GrAAType aaType = GrAAType::kNone,
AATypeFlags aaTypeFlags = AATypeFlags::kNone,
GrStyle style = GrStyle(SkStrokeRec::kFill_InitStyle)) {
sk_sp<GrContext> ctx = GrContext::MakeMock(nullptr);
// The cache needs to be big enough that nothing gets flushed, or our expectations can be wrong
@ -96,7 +98,7 @@ static void test_path(skiatest::Reporter* reporter,
REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, 0));
// Draw the path, check that new resource count matches expectations
draw_path(ctx.get(), rtc.get(), path, pathRenderer.get(), aaType, style);
draw_path(ctx.get(), rtc.get(), path, pathRenderer.get(), aaTypeFlags, style);
ctx->flush();
REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected));
@ -129,7 +131,8 @@ DEF_GPUTEST(TessellatingPathRendererCacheTest, reporter, /* options */) {
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(1);
GrStyle style(paint);
test_path(reporter, create_concave_path, createPR, kExpectedResources, GrAAType::kNone, style);
test_path(
reporter, create_concave_path, createPR, kExpectedResources, AATypeFlags::kNone, style);
}
// Test that deleting the original path invalidates the textures cached by the SW path renderer
@ -142,7 +145,7 @@ DEF_GPUTEST(SoftwarePathRendererCacheTest, reporter, /* options */) {
// only contains a single quad so GrFillRectOp doesn't need to use the shared index buffer.
const int kExpectedResources = 1;
test_path(reporter, create_concave_path, createPR, kExpectedResources, GrAAType::kCoverage);
test_path(reporter, create_concave_path, createPR, kExpectedResources, AATypeFlags::kCoverage);
// Test with a style that alters the path geometry. This needs to attach the invalidation logic
// to the original path, not the modified path produced by the style.
@ -150,6 +153,6 @@ DEF_GPUTEST(SoftwarePathRendererCacheTest, reporter, /* options */) {
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(1);
GrStyle style(paint);
test_path(reporter, create_concave_path, createPR, kExpectedResources, GrAAType::kCoverage,
test_path(reporter, create_concave_path, createPR, kExpectedResources, AATypeFlags::kCoverage,
style);
}

View File

@ -633,11 +633,13 @@ static std::unique_ptr<GrFragmentProcessor> create_linear_gradient_processor(GrC
return as_SB(shader)->asFragmentProcessor(args);
}
using AATypeFlags = GrPathRenderer::AATypeFlags;
static void test_path(GrContext* ctx,
GrRenderTargetContext* renderTargetContext,
const SkPath& path,
const SkMatrix& matrix = SkMatrix::I(),
GrAAType aaType = GrAAType::kNone,
AATypeFlags aaTypeFlags = AATypeFlags::kNone,
std::unique_ptr<GrFragmentProcessor> fp = nullptr) {
GrTessellatingPathRenderer tess;
@ -660,7 +662,7 @@ static void test_path(GrContext* ctx,
&clipConservativeBounds,
&matrix,
&shape,
aaType,
aaTypeFlags,
false};
tess.drawPath(args);
}
@ -699,31 +701,31 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(TessellatingPathRendererTests, reporter, ctxInfo) {
test_path(ctx, rtc.get(), create_path_16());
SkMatrix nonInvertibleMatrix = SkMatrix::MakeScale(0, 0);
std::unique_ptr<GrFragmentProcessor> fp(create_linear_gradient_processor(ctx));
test_path(ctx, rtc.get(), create_path_17(), nonInvertibleMatrix, GrAAType::kCoverage,
test_path(ctx, rtc.get(), create_path_17(), nonInvertibleMatrix, AATypeFlags::kCoverage,
std::move(fp));
test_path(ctx, rtc.get(), create_path_18());
test_path(ctx, rtc.get(), create_path_19());
test_path(ctx, rtc.get(), create_path_20(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_21(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_20(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_21(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_23());
test_path(ctx, rtc.get(), create_path_24());
test_path(ctx, rtc.get(), create_path_25(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_26(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_27(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_28(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_25(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_26(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_27(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_28(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_29());
test_path(ctx, rtc.get(), create_path_30());
test_path(ctx, rtc.get(), create_path_31(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_31(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_32());
test_path(ctx, rtc.get(), create_path_33());
test_path(ctx, rtc.get(), create_path_34());
test_path(ctx, rtc.get(), create_path_35());
test_path(ctx, rtc.get(), create_path_36());
test_path(ctx, rtc.get(), create_path_37());
test_path(ctx, rtc.get(), create_path_38(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_38(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_39());
test_path(ctx, rtc.get(), create_path_40());
test_path(ctx, rtc.get(), create_path_41(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_41(), SkMatrix(), AATypeFlags::kCoverage);
test_path(ctx, rtc.get(), create_path_42());
test_path(ctx, rtc.get(), create_path_43(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_43(), SkMatrix(), AATypeFlags::kCoverage);
}