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