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