xref: /aosp_15_r20/external/skia/src/gpu/ganesh/tessellate/PathTessellator.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 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 #ifndef PathTessellator_DEFINED
9 #define PathTessellator_DEFINED
10 
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/private/SkColorData.h"
15 #include "src/base/SkArenaAlloc.h"
16 #include "src/gpu/ganesh/GrGpuBuffer.h"
17 #include "src/gpu/ganesh/GrVertexChunkArray.h"
18 #include "src/gpu/ganesh/geometry/GrInnerFanTriangulator.h"
19 #include "src/gpu/tessellate/Tessellation.h"
20 
21 #include <tuple>
22 
23 class GrMeshDrawTarget;
24 class GrOpFlushState;
25 
26 namespace skgpu::ganesh {
27 
28 // Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass,
29 // the caller may or may not be required to draw the path's inner fan separately.
30 class PathTessellator {
31 public:
32     using PatchAttribs = tess::PatchAttribs;
33 
34     struct PathDrawList {
35         PathDrawList(const SkMatrix& pathMatrix,
36                      const SkPath& path,
37                      const SkPMColor4f& color,
38                      PathDrawList* next = nullptr)
fPathMatrixPathDrawList39                 : fPathMatrix(pathMatrix), fPath(path), fColor(color), fNext(next) {}
40 
41         SkMatrix fPathMatrix;
42         SkPath fPath;
43         SkPMColor4f fColor;
44         PathDrawList* fNext;
45 
46         struct Iter {
47             void operator++() { fHead = fHead->fNext; }
48             bool operator!=(const Iter& b) const { return fHead != b.fHead; }
49             std::tuple<const SkMatrix&, const SkPath&, const SkPMColor4f&> operator*() const {
50                 return {fHead->fPathMatrix, fHead->fPath, fHead->fColor};
51             }
52             const PathDrawList* fHead;
53         };
beginPathDrawList54         Iter begin() const { return {this}; }
endPathDrawList55         Iter end() const { return {nullptr}; }
56     };
57 
~PathTessellator()58     virtual ~PathTessellator() {}
59 
patchAttribs()60     PatchAttribs patchAttribs() const { return fAttribs; }
61 
62     // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
63     virtual void prepare(GrMeshDrawTarget* target,
64                          const SkMatrix& shaderMatrix,
65                          const PathDrawList& pathDrawList,
66                          int totalCombinedPathVerbCnt) = 0;
67 
68     // Issues fixed-count instanced draw calls over the patches. The caller is responsible for
69     // binding its desired pipeline ahead of time.
70     virtual void draw(GrOpFlushState* flushState) const = 0;
71 
72 protected:
PathTessellator(bool infinitySupport,PatchAttribs attribs)73     PathTessellator(bool infinitySupport, PatchAttribs attribs) : fAttribs(attribs) {
74         if (!infinitySupport) {
75             fAttribs |= PatchAttribs::kExplicitCurveType;
76         }
77     }
78 
79     PatchAttribs fAttribs;
80 
81     GrVertexChunkArray fVertexChunkArray;
82     // The max number of vertices that must be drawn to account for the accumulated tessellation
83     // levels of the written patches.
84     int fMaxVertexCount = 0;
85 
86     sk_sp<const GrGpuBuffer> fFixedVertexBuffer;
87     sk_sp<const GrGpuBuffer> fFixedIndexBuffer;
88 };
89 
90 // Draws an array of "outer curve" patches. Each patch is an independent 4-point curve, representing
91 // either a cubic or a conic. Quadratics are converted to cubics and triangles are converted to
92 // conics with w=Inf.
93 class PathCurveTessellator final : public PathTessellator {
94 public:
95     static PathCurveTessellator* Make(SkArenaAlloc* arena,
96                                       bool infinitySupport,
97                                       PatchAttribs attribs = PatchAttribs::kNone) {
98         return arena->make<PathCurveTessellator>(infinitySupport, attribs);
99     }
100 
101     PathCurveTessellator(bool infinitySupport,
102                          PatchAttribs attribs = PatchAttribs::kNone)
PathTessellator(infinitySupport,attribs)103             : PathTessellator(infinitySupport, attribs) {}
104 
105     void prepareWithTriangles(GrMeshDrawTarget* target,
106                               const SkMatrix& shaderMatrix,
107                               GrInnerFanTriangulator::BreadcrumbTriangleList* extraTriangles,
108                               const PathDrawList& pathDrawList,
109                               int totalCombinedPathVerbCnt);
110 
prepare(GrMeshDrawTarget * target,const SkMatrix & shaderMatrix,const PathDrawList & pathDrawList,int totalCombinedPathVerbCnt)111     void prepare(GrMeshDrawTarget* target,
112                  const SkMatrix& shaderMatrix,
113                  const PathDrawList& pathDrawList,
114                  int totalCombinedPathVerbCnt) final {
115         this->prepareWithTriangles(target,
116                                    shaderMatrix,
117                                    nullptr, // no extra triangles by default
118                                    pathDrawList,
119                                    totalCombinedPathVerbCnt);
120     }
121 
122     void draw(GrOpFlushState*) const final;
123 
124     // Draws a 4-point instance for each patch. This method is used for drawing convex hulls over
125     // each cubic with GrFillCubicHullShader. The caller is responsible for binding its desired
126     // pipeline ahead of time.
127     void drawHullInstances(GrOpFlushState*, sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const;
128 };
129 
130 // Prepares an array of "wedge" patches. A wedge is an independent, 5-point closed contour
131 // consisting of 4 control points plus an anchor point fanning from the center of the curve's
132 // resident contour. A wedge can be either a cubic or a conic. Quadratics and lines are converted to
133 // cubics. Once stencilled, these wedges alone define the complete path.
134 class PathWedgeTessellator final : public PathTessellator {
135 public:
136     static PathWedgeTessellator* Make(SkArenaAlloc* arena,
137                                       bool infinitySupport,
138                                       PatchAttribs attribs = PatchAttribs::kNone) {
139         return arena->make<PathWedgeTessellator>(infinitySupport, attribs);
140     }
141 
142     PathWedgeTessellator(bool infinitySupport, PatchAttribs attribs = PatchAttribs::kNone)
PathTessellator(infinitySupport,attribs)143             : PathTessellator(infinitySupport, attribs) {
144         fAttribs |= PatchAttribs::kFanPoint;
145     }
146 
147     void prepare(GrMeshDrawTarget* target,
148                  const SkMatrix& shaderMatrix,
149                  const PathDrawList& pathDrawList,
150                  int totalCombinedPathVerbCnt) final;
151 
152     void draw(GrOpFlushState*) const final;
153 };
154 
155 }  // namespace skgpu::ganesh
156 
157 #endif  // PathTessellator_DEFINED
158