[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:
parent
60bd1cf8fb
commit
0cdd5d7828
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user