• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "experimental/graphite/src/Renderer.h"
9 
10 #include "experimental/graphite/src/DrawWriter.h"
11 #include "experimental/graphite/src/UniformManager.h"
12 #include "experimental/graphite/src/geom/Shape.h"
13 #include "experimental/graphite/src/geom/Transform_graphite.h"
14 #include "include/core/SkPathTypes.h"
15 #include "include/core/SkRect.h"
16 #include "src/core/SkUniformData.h"
17 #include "src/gpu/BufferWriter.h"
18 #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
19 
20 namespace skgpu {
21 
22 namespace {
23 
24 // TODO: These settings are actually shared by tessellating path renderers, so will be exposed later
25 
26 // Returns the stencil settings to use for a standard Redbook "stencil" pass.
fillrule_settings(bool evenOdd)27 constexpr DepthStencilSettings fillrule_settings(bool evenOdd) {
28     // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
29     constexpr DepthStencilSettings::Face kIncCW = {
30         /*stencilFail=*/   StencilOp::kKeep,
31         /*depthFail=*/     StencilOp::kKeep,
32         /*dsPass=*/        StencilOp::kIncWrap,
33         /*stencilCompare=*/CompareOp::kAlways,
34         /*readMask=*/      0xffffffff,
35         /*writeMask=*/     0xffffffff
36     };
37     constexpr DepthStencilSettings::Face kDecCCW = {
38         /*stencilFail=*/   StencilOp::kKeep,
39         /*depthFail=*/     StencilOp::kKeep,
40         /*dsPass=*/        StencilOp::kDecWrap,
41         /*stencilCompare=*/CompareOp::kAlways,
42         /*readMask=*/      0xffffffff,
43         /*writeMask=*/     0xffffffff
44     };
45 
46     // Toggles the bottom stencil bit. Used for "even-odd" fill.
47     constexpr DepthStencilSettings::Face kToggle = {
48         /*stencilFail=*/   StencilOp::kKeep,
49         /*depthFail=*/     StencilOp::kKeep,
50         /*dsPass=*/        StencilOp::kInvert,
51         /*stencilCompare=*/CompareOp::kAlways,
52         /*readMask=*/      0xffffffff,
53         /*writeMask=*/     0x00000001
54     };
55 
56     // Always use ref = 0, disable depths, but still use greater depth test.
57     constexpr DepthStencilSettings kWindingFill = {
58         /*frontStencil=*/kIncCW,
59         /*backStencil=*/ kDecCCW,
60         /*refValue=*/    0,
61         /*stencilTest=*/ true,
62         /*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
63         /*depthTest=*/   true,
64         /*depthWrite=*/  false
65     };
66     constexpr DepthStencilSettings kEvenOddFill = {
67         /*frontStencil=*/kToggle,
68         /*backStencil=*/ kToggle,
69         /*refValue=*/    0,
70         /*stencilTest=*/ true,
71         /*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
72         /*depthTest=*/   true,
73         /*depthWrite=*/  false
74     };
75 
76     return evenOdd ? kEvenOddFill : kWindingFill;
77 }
78 
79 // Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
80 // stencil values to pass and write a color, and resets the stencil value back to zero; discards
81 // immediately on stencil values of zero (or does the inverse of these operations when the path
82 // requires filling everything else).
cover_settings(bool inverse)83 constexpr DepthStencilSettings cover_settings(bool inverse) {
84     // Resets non-zero bits to 0, passes when not zero. We set depthFail to kZero because if we
85     // encounter that case, the kNotEqual=0 stencil test passed, so it does need to be set back to 0
86     // and the dsPass op won't be run. In practice, since the stencil steps will fail the same depth
87     // test, the stencil value will likely not be non-zero, but best to be explicit.
88     constexpr DepthStencilSettings::Face kNormal = {
89         /*stencilFail=*/   StencilOp::kKeep,
90         /*depthFail=*/     StencilOp::kZero,
91         /*dsPass=*/        StencilOp::kZero,
92         /*stencilCompare=*/CompareOp::kNotEqual,
93         /*readMask=*/      0xffffffff,
94         /*writeMask=*/     0xffffffff
95     };
96 
97     // Resets non-zero bits to 0, passes when zero
98     constexpr DepthStencilSettings::Face kInverted = {
99         /*stencilFail=*/   StencilOp::kZero,
100         /*depthFail=*/     StencilOp::kKeep,
101         /*dsPass=*/        StencilOp::kKeep,
102         /*stencilCompare=*/CompareOp::kEqual,
103         /*readMask=*/      0xffffffff,
104         /*writeMask=*/     0xffffffff
105     };
106 
107     // Always use ref = 0, enabled depth writes, and greater depth test, both
108     // front and back use the same stencil settings.
109     constexpr DepthStencilSettings kNormalDSS = {
110         /*frontStencil=*/kNormal,
111         /*frontStencil=*/kNormal,
112         /*refValue=*/    0,
113         /*stencilTest=*/ true,
114         /*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
115         /*depthTest=*/   true,
116         /*depthWrite=*/  true
117     };
118     constexpr DepthStencilSettings kInvertedDSS = {
119         /*frontStencil=*/kInverted,
120         /*backStencil=*/ kInverted,
121         /*refValue=*/    0,
122         /*stencilTest=*/ true,
123         /*depthCompare=*/CompareOp::kAlways, // kGreater once steps know the right depth value
124         /*depthTest=*/   true,
125         /*depthWrite=*/  true
126     };
127     return inverse ? kInvertedDSS : kNormalDSS;
128 }
129 
130 class StencilFanRenderStep final : public RenderStep {
131 public:
StencilFanRenderStep(bool evenOdd)132     StencilFanRenderStep(bool evenOdd)
133             : RenderStep(Flags::kRequiresMSAA,
134                          /*uniforms=*/{},
135                          PrimitiveType::kTriangles,
136                          fillrule_settings(evenOdd),
137                          /*vertexAttrs=*/{{"position",
138                                            VertexAttribType::kFloat3,
139                                            SkSLType::kFloat3}},
140                          /*instanceAttrs=*/{}) {}
141 
~StencilFanRenderStep()142     ~StencilFanRenderStep() override {}
143 
name() const144     const char* name() const override { return "stencil-fan"; }
145 
vertexSkSL() const146     const char* vertexSkSL() const override {
147         return "     float4 devPosition = float4(position.xy, 0.0, position.z);\n";
148     }
149 
writeVertices(DrawWriter * writer,const SkIRect & bounds,const Transform & localToDevice,const Shape & shape) const150     void writeVertices(DrawWriter* writer,
151                        const SkIRect& bounds,
152                        const Transform& localToDevice,
153                        const Shape& shape) const override {
154         // TODO: Have Shape provide a path-like iterator so we don't actually have to convert non
155         // paths to SkPath just to iterate their pts/verbs
156         SkPath path = shape.asPath();
157         DrawWriter::Vertices verts{*writer};
158         for (PathMiddleOutFanIter it(path); !it.done();) {
159             for (auto [p0, p1, p2] : it.nextStack()) {
160                 // TODO: PathMiddleOutFanIter should use SkV2 instead of SkPoint?
161                 SkV2 p[3] = {{p0.fX, p0.fY}, {p1.fX, p1.fY}, {p2.fX, p2.fY}};
162                 SkV4 devPoints[3];
163                 localToDevice.mapPoints(p, devPoints, 3);
164 
165                 // TODO: Support reserving maxTrianglesInFans*3 vertices outside the loop, with
166                 // automatic returns of unused verts.
167                 verts.append(3) << devPoints[0].x << devPoints[0].y << devPoints[0].w  // p0
168                                 << devPoints[1].x << devPoints[1].y << devPoints[1].w  // p1
169                                 << devPoints[2].x << devPoints[2].y << devPoints[2].w; // p2
170             }
171         }
172     }
173 
writeUniforms(Layout layout,const SkIRect &,const Transform &,const Shape &) const174     sk_sp<SkUniformData> writeUniforms(Layout layout,
175                                        const SkIRect&,
176                                        const Transform&,
177                                        const Shape&) const override {
178         // Control points are pre-transformed to device space on the CPU, so no uniforms needed.
179         return nullptr;
180     }
181 };
182 
183 // TODO: Hand off to csmartdalton, this should roughly correspond to the fStencilPathProgram stage
184 // of skgpu::v1::PathStencilCoverOp using the PathCurveTessellator
185 /*
186 class StencilCurvesRenderStep : public RenderStep {
187 public:
188     StencilCurvesRenderStep() {}
189 
190     ~StencilCurvesRenderStep() override {}
191 
192     const char* name()            const override { return "stencil-curves"; }
193     bool        requiresStencil() const override { return true;  }
194     bool        requiresMSAA()    const override { return true;  }
195     bool        performsShading() const override { return false; }
196 
197 private:
198 };
199 */
200 
201 // TODO: Hand off to csmartdalton, this should roughly correspond to the fCoverBBoxProgram stage
202 // of skgpu::v1::PathStencilCoverOp.
203 class FillBoundsRenderStep final : public RenderStep {
204 public:
205     // TODO: Will need to add kRequiresStencil when we support specifying stencil settings and
206     // the Renderer includes the stenciling step first.
FillBoundsRenderStep(bool inverseFill)207     FillBoundsRenderStep(bool inverseFill)
208             : RenderStep(Flags::kPerformsShading,
209                          /*uniforms=*/{},
210                          PrimitiveType::kTriangles,
211                          cover_settings(inverseFill),
212                          /*vertexAttrs=*/{{"position",
213                                            VertexAttribType::kFloat3,
214                                            SkSLType::kFloat3}},
215                          /*instanceAttrs=*/{})
216             , fInverseFill(inverseFill) {}
217 
~FillBoundsRenderStep()218     ~FillBoundsRenderStep() override {}
219 
name() const220     const char* name() const override { return "fill-bounds"; }
221 
vertexSkSL() const222     const char* vertexSkSL() const override {
223         return "     float4 devPosition = float4(position.xy, 0.0, position.z);\n";
224     }
225 
writeVertices(DrawWriter * writer,const SkIRect & bounds,const Transform & localToDevice,const Shape & shape) const226     void writeVertices(DrawWriter* writer,
227                        const SkIRect& bounds,
228                        const Transform& localToDevice,
229                        const Shape& shape) const override {
230         SkV4 devPoints[4]; // ordered TL, TR, BR, BL
231 
232         if (fInverseFill) {
233             // TODO: When we handle local coords, we'd need to map these corners by the inverse.
234             devPoints[0] = {(float) bounds.fLeft,  (float) bounds.fTop,    0.f, 1.f};
235             devPoints[1] = {(float) bounds.fRight, (float) bounds.fTop,    0.f, 1.f};
236             devPoints[2] = {(float) bounds.fRight, (float) bounds.fBottom, 0.f, 1.f};
237             devPoints[3] = {(float) bounds.fLeft,  (float) bounds.fBottom, 0.f, 1.f};
238         } else {
239             localToDevice.mapPoints(shape.bounds(), devPoints);
240         }
241 
242         DrawWriter::Vertices verts{*writer};
243         verts.append(6) << devPoints[0].x << devPoints[0].y << devPoints[0].w // TL
244                         << devPoints[3].x << devPoints[3].y << devPoints[3].w // BL
245                         << devPoints[1].x << devPoints[1].y << devPoints[1].w // TR
246                         << devPoints[1].x << devPoints[1].y << devPoints[1].w // TR
247                         << devPoints[3].x << devPoints[3].y << devPoints[3].w // BL
248                         << devPoints[2].x << devPoints[2].y << devPoints[2].w;// BR
249     }
250 
writeUniforms(Layout layout,const SkIRect &,const Transform & localToDevice,const Shape &) const251     sk_sp<SkUniformData> writeUniforms(Layout layout,
252                                        const SkIRect&,
253                                        const Transform& localToDevice,
254                                        const Shape&) const override {
255         // Positions are pre-transformed on the CPU so no uniforms needed
256         return nullptr;
257     }
258 
259 private:
260     const bool fInverseFill;
261 };
262 
263 } // anonymous namespace
264 
StencilAndFillPath(SkPathFillType fillType)265 const Renderer& Renderer::StencilAndFillPath(SkPathFillType fillType) {
266     // Because each fill type uses a different stencil settings, there is one Renderer per type.
267     // However, at each stage (stencil vs. cover), there are only two RenderSteps to branch on.
268     static const StencilFanRenderStep kWindingStencilFan{false};
269     static const StencilFanRenderStep kEvenOddStencilFan{true};
270     static const FillBoundsRenderStep kFill{false};
271     static const FillBoundsRenderStep kInverseFill{true};
272 
273     // TODO: Uncomment and include the curve stenciling steps to draw curved paths
274     static const Renderer kWindingRenderer{"stencil-and-fill[winding]",
275                                            &kWindingStencilFan,
276                                            /*&kWindingStencilCurves,*/
277                                            &kFill};
278     static const Renderer kInverseWindingRenderer{"stencil-and-fill[inverse-winding]",
279                                                   &kWindingStencilFan,
280                                                   /*&kWindingStencilCurves,*/
281                                                   &kInverseFill};
282     static const Renderer kEvenOddRenderer{"stencil-and-fill[evenodd]",
283                                            &kEvenOddStencilFan,
284                                            /*&kEvenOddStencilCurves,*/
285                                            &kFill};
286     static const Renderer kInverseEvenOddRenderer{"stencil-and-fill[inverse-evenodd]",
287                                                   &kEvenOddStencilFan,
288                                                   /*&kEvenOddStencilCurves,*/
289                                                   &kInverseFill};
290 
291     switch(fillType) {
292         case SkPathFillType::kWinding: return kWindingRenderer;
293         case SkPathFillType::kEvenOdd: return kEvenOddRenderer;
294         case SkPathFillType::kInverseWinding: return kInverseWindingRenderer;
295         case SkPathFillType::kInverseEvenOdd: return kInverseEvenOddRenderer;
296     }
297     SkUNREACHABLE;
298 }
299 
300 } // namespace skgpu
301