[graphite] Implement middle-out triangle stencil RenderStep

Cq-Include-Trybots: luci.skia.skia.primary:Test-Mac11-Clang-MacMini9.1-GPU-AppleM1-arm64-Release-All-Graphite,Test-Mac11-Clang-MacMini9.1-GPU-AppleM1-arm64-Debug-All-ASAN_Graphite,Build-Mac-Clang-arm64-Release-iOS_Graphite,Build-Mac-Clang-arm64-Release-Graphite,Build-Mac-Clang-arm64-Debug-iOS_Graphite,Build-Mac-Clang-arm64-Debug-Graphite_NoGpu,Build-Mac-Clang-arm64-Debug-Graphite,Build-Mac-Clang-arm64-Debug-ASAN_Graphite
Bug: skia:12703
Change-Id: I1e0d004d5688b78f0cdaa9df31b27831415fba6c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/484561
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2021-12-22 16:44:40 -05:00 committed by SkCQ
parent 60bd1cf8fb
commit 0cdd5d7828

View File

@ -15,6 +15,7 @@
#include "include/core/SkPathTypes.h"
#include "include/core/SkRect.h"
#include "src/gpu/BufferWriter.h"
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
namespace skgpu {
@ -22,6 +23,59 @@ namespace {
// TODO: These settings are actually shared by tessellating path renderers, so will be exposed later
// Returns the stencil settings to use for a standard Redbook "stencil" pass.
constexpr DepthStencilSettings fillrule_settings(bool evenOdd) {
// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
constexpr DepthStencilSettings::Face kIncCW = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kIncWrap,
/*stencilCompare=*/CompareOp::kAlways,
/*readMask=*/ 0xffffffff,
/*writeMask=*/ 0xffffffff
};
constexpr DepthStencilSettings::Face kDecCCW = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kDecWrap,
/*stencilCompare=*/CompareOp::kAlways,
/*readMask=*/ 0xffffffff,
/*writeMask=*/ 0xffffffff
};
// Toggles the bottom stencil bit. Used for "even-odd" fill.
constexpr DepthStencilSettings::Face kToggle = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kInvert,
/*stencilCompare=*/CompareOp::kAlways,
/*readMask=*/ 0xffffffff,
/*writeMask=*/ 0x00000001
};
// Always use ref = 0, disable depths, but still use greater depth test.
constexpr DepthStencilSettings kWindingFill = {
/*frontStencil=*/kIncCW,
/*backStencil=*/ kDecCCW,
/*refValue=*/ 0,
/*stencilTest=*/ true,
/*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
/*depthTest=*/ true,
/*depthWrite=*/ false
};
constexpr DepthStencilSettings kEvenOddFill = {
/*frontStencil=*/kToggle,
/*backStencil=*/ kToggle,
/*refValue=*/ 0,
/*stencilTest=*/ true,
/*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
/*depthTest=*/ true,
/*depthWrite=*/ false
};
return evenOdd ? kEvenOddFill : kWindingFill;
}
// Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
// stencil values to pass and write a color, and resets the stencil value back to zero; discards
// immediately on stencil values of zero (or does the inverse of these operations when the path
@ -35,7 +89,7 @@ constexpr DepthStencilSettings cover_settings(bool inverse) {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kZero,
/*dsPass=*/ StencilOp::kZero,
/*stencilCompare=*/CompareOp::kEqual, // TODO: Actually kNotEqual once we have stencil steps
/*stencilCompare=*/CompareOp::kNotEqual,
/*readMask=*/ 0xffffffff,
/*writeMask=*/ 0xffffffff
};
@ -73,23 +127,57 @@ constexpr DepthStencilSettings cover_settings(bool inverse) {
return inverse ? kInvertedDSS : kNormalDSS;
}
// TODO: Hand off to csmartdalton, this should roughly correspond to the fStencilFanProgram and
// simple triangulator shader stage of the skgpu::v1::PathStencilCoverOp
/*
class StencilFanRenderStep : public RenderStep {
class StencilFanRenderStep final : public RenderStep {
public:
StencilFanRenderStep() {}
StencilFanRenderStep(bool evenOdd)
: RenderStep(Flags::kRequiresMSAA,
/*uniforms=*/{},
PrimitiveType::kTriangles,
fillrule_settings(evenOdd),
/*vertexAttrs=*/{{"position", VertexAttribType::kFloat3, SLType::kFloat3}},
/*instanceAttrs=*/{}) {}
~StencilFanRenderStep() override {}
const char* name() const override { return "stencil-fan"; }
bool requiresStencil() const override { return true; }
bool requiresMSAA() const override { return true; }
bool performsShading() const override { return false; }
const char* name() const override { return "stencil-fan"; }
private:
const char* vertexSkSL() const override {
return " float4 devPosition = float4(position.xy, 0.0, position.z);\n";
}
void writeVertices(DrawWriter* writer,
const SkIRect& bounds,
const Transform& localToDevice,
const Shape& shape) const override {
// TODO: Have Shape provide a path-like iterator so we don't actually have to convert non
// paths to SkPath just to iterate their pts/verbs
SkPath path = shape.asPath();
for (PathMiddleOutFanIter it(path); !it.done();) {
for (auto [p0, p1, p2] : it.nextStack()) {
// TODO: PathMiddleOutFanIter should use SkV2 instead of SkPoint?
SkV2 p[3] = {{p0.fX, p0.fY}, {p1.fX, p1.fY}, {p2.fX, p2.fY}};
SkV4 devPoints[3];
localToDevice.mapPoints(p, devPoints, 3);
// TODO: Instead do one appendVertices(maxTrianglsInFans*3) and then return vertices
// at the end to avoid redundant bounds/offset checking in the DrawWriter.
auto vw = writer->appendVertices(3);
vw << devPoints[0].x << devPoints[0].y << devPoints[0].w // p0
<< devPoints[1].x << devPoints[1].y << devPoints[1].w // p1
<< devPoints[2].x << devPoints[2].y << devPoints[2].w; // p2
}
}
}
sk_sp<UniformData> writeUniforms(Layout layout,
const SkIRect&,
const Transform&,
const Shape&) const override {
// Control points are pre-transformed to device space on the CPU, so no uniforms needed.
return nullptr;
}
};
*/
// TODO: Hand off to csmartdalton, this should roughly correspond to the fStencilPathProgram stage
// of skgpu::v1::PathStencilCoverOp using the PathCurveTessellator
@ -172,25 +260,36 @@ private:
} // anonymous namespace
const Renderer& Renderer::StencilAndFillPath(SkPathFillType fillType) {
// TODO: Uncomment and include in kRenderer to draw flattened paths instead of bboxes
// static const StencilFanRenderStep kStencilFan;
// TODO: Uncomment and include in kRenderer to draw curved paths
// static const StencilCurvesRenderStep kStencilCurves;
// TODO: This could move into a header and be reused across renderers
// Because each fill type uses a different stencil settings, there is one Renderer per type.
// However, at each stage (stencil vs. cover), there are only two RenderSteps to branch on.
static const StencilFanRenderStep kWindingStencilFan{false};
static const StencilFanRenderStep kEvenOddStencilFan{true};
static const FillBoundsRenderStep kFill{false};
static const FillBoundsRenderStep kInverseFill{true};
// TODO: Combine these two with stencil steps for winding and even-odd.
static const Renderer kFillRenderer("stencil-and-fill[]", &kFill);
static const Renderer kInverseFillRenderer("stencil-and-fill[inverse]", &kInverseFill);
// TODO: Uncomment and include the curve stenciling steps to draw curved paths
static const Renderer kWindingRenderer{"stencil-and-fill[winding]",
&kWindingStencilFan,
/*&kWindingStencilCurves,*/
&kFill};
static const Renderer kInverseWindingRenderer{"stencil-and-fill[inverse-winding]",
&kWindingStencilFan,
/*&kWindingStencilCurves,*/
&kInverseFill};
static const Renderer kEvenOddRenderer{"stencil-and-fill[evenodd]",
&kEvenOddStencilFan,
/*&kEvenOddStencilCurves,*/
&kFill};
static const Renderer kInverseEvenOddRenderer{"stencil-and-fill[inverse-evenodd]",
&kEvenOddStencilFan,
/*&kEvenOddStencilCurves,*/
&kInverseFill};
switch (fillType) {
case SkPathFillType::kWinding: [[fallthrough]];
case SkPathFillType::kEvenOdd:
return kFillRenderer;
case SkPathFillType::kInverseWinding: [[fallthrough]];
case SkPathFillType::kInverseEvenOdd:
return kInverseFillRenderer;
switch(fillType) {
case SkPathFillType::kWinding: return kWindingRenderer;
case SkPathFillType::kEvenOdd: return kEvenOddRenderer;
case SkPathFillType::kInverseWinding: return kInverseWindingRenderer;
case SkPathFillType::kInverseEvenOdd: return kInverseEvenOddRenderer;
}
SkUNREACHABLE;
}