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 #ifndef tessellate_PathTessellator_DEFINED 9 #define tessellate_PathTessellator_DEFINED 10 11 #include "src/gpu/tessellate/Tessellation.h" 12 13 class SkPath; 14 15 #if SK_GPU_V1 16 17 #include "src/gpu/GrVertexChunkArray.h" 18 #include "src/gpu/tessellate/PatchWriter.h" 19 20 class GrGpuBuffer; 21 class GrMeshDrawTarget; 22 class GrOpFlushState; 23 24 #endif 25 26 namespace skgpu { 27 28 class PatchWriter; 29 30 // Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass, 31 // the caller may or may not be required to draw the path's inner fan separately. 32 class PathTessellator { 33 public: 34 // This is the maximum number of segments contained in our vertex and index buffers for 35 // fixed-count rendering. If rendering in fixed-count mode and a curve requires more segments, 36 // it must be chopped. 37 constexpr static int kMaxFixedResolveLevel = 5; 38 39 struct PathDrawList { 40 PathDrawList(const SkMatrix& pathMatrix, 41 const SkPath& path, 42 const SkPMColor4f& color, 43 PathDrawList* next = nullptr) fPathMatrixPathDrawList44 : fPathMatrix(pathMatrix), fPath(path), fColor(color), fNext(next) {} 45 46 SkMatrix fPathMatrix; 47 SkPath fPath; 48 SkPMColor4f fColor; 49 PathDrawList* fNext; 50 51 struct Iter { 52 void operator++() { fHead = fHead->fNext; } 53 bool operator!=(const Iter& b) const { return fHead != b.fHead; } 54 std::tuple<const SkMatrix&, const SkPath&, const SkPMColor4f&> operator*() const { 55 return {fHead->fPathMatrix, fHead->fPath, fHead->fColor}; 56 } 57 const PathDrawList* fHead; 58 }; beginPathDrawList59 Iter begin() const { return {this}; } endPathDrawList60 Iter end() const { return {nullptr}; } 61 }; 62 ~PathTessellator()63 virtual ~PathTessellator() {} 64 patchAttribs()65 PatchAttribs patchAttribs() const { return fAttribs; } 66 67 // Gives an approximate initial buffer size for this class to write patches into. Ideally the 68 // whole path will fit into this initial buffer, but if it requires a lot of chopping, the 69 // PatchWriter will allocate more buffer(s). 70 virtual int patchPreallocCount(int totalCombinedPathVerbCnt) const = 0; 71 72 // Writes out patches to the given PatchWriter, chopping as necessary so the curves all fit in 73 // maxTessellationSegments or fewer. 74 // 75 // Each path's fPathMatrix in the list is applied on the CPU while the geometry is being written 76 // out. This is a tool for batching, and is applied in addition to the shader's on-GPU matrix. 77 virtual void writePatches(PatchWriter&, 78 int maxTessellationSegments, 79 const SkMatrix& shaderMatrix, 80 const PathDrawList&) = 0; 81 82 #if SK_GPU_V1 83 // Initializes the internal vertex and index buffers required for drawFixedCount(). 84 virtual void prepareFixedCountBuffers(GrMeshDrawTarget*) = 0; 85 86 // Called before draw(). Prepares GPU buffers containing the geometry to tessellate. prepare(GrMeshDrawTarget * target,int maxTessellationSegments,const SkMatrix & shaderMatrix,const PathDrawList & pathDrawList,int totalCombinedPathVerbCnt,bool willUseTessellationShaders)87 void prepare(GrMeshDrawTarget* target, 88 int maxTessellationSegments, 89 const SkMatrix& shaderMatrix, 90 const PathDrawList& pathDrawList, 91 int totalCombinedPathVerbCnt, 92 bool willUseTessellationShaders) { 93 if (int patchPreallocCount = this->patchPreallocCount(totalCombinedPathVerbCnt)) { 94 PatchWriter patchWriter(target, this, patchPreallocCount); 95 this->writePatches(patchWriter, maxTessellationSegments, shaderMatrix, pathDrawList); 96 } 97 if (!willUseTessellationShaders) { 98 this->prepareFixedCountBuffers(target); 99 } 100 } 101 102 // Issues hardware tessellation draw calls over the patches. The caller is responsible for 103 // binding its desired pipeline ahead of time. 104 virtual void drawTessellated(GrOpFlushState*) const = 0; 105 106 // Issues fixed-count instanced draw calls over the patches. The caller is responsible for 107 // binding its desired pipeline ahead of time. 108 virtual void drawFixedCount(GrOpFlushState*) const = 0; 109 draw(GrOpFlushState * flushState,bool willUseTessellationShaders)110 void draw(GrOpFlushState* flushState, bool willUseTessellationShaders) { 111 if (willUseTessellationShaders) { 112 this->drawTessellated(flushState); 113 } else { 114 this->drawFixedCount(flushState); 115 } 116 } 117 #endif 118 119 // Returns an upper bound on the number of combined edges there might be from all inner fans in 120 // a PathDrawList. MaxCombinedFanEdgesInPathDrawList(int totalCombinedPathVerbCnt)121 static int MaxCombinedFanEdgesInPathDrawList(int totalCombinedPathVerbCnt) { 122 // Path fans might have an extra edge from an implicit kClose at the end, but they also 123 // always begin with kMove. So the max possible number of edges in a single path is equal to 124 // the number of verbs. Therefore, the max number of combined fan edges in a PathDrawList is 125 // the number of combined path verbs in that PathDrawList. 126 return totalCombinedPathVerbCnt; 127 } 128 129 protected: 130 // How many triangles are in a curve with 2^resolveLevel line segments? NumCurveTrianglesAtResolveLevel(int resolveLevel)131 constexpr static int NumCurveTrianglesAtResolveLevel(int resolveLevel) { 132 // resolveLevel=0 -> 0 line segments -> 0 triangles 133 // resolveLevel=1 -> 2 line segments -> 1 triangle 134 // resolveLevel=2 -> 4 line segments -> 3 triangles 135 // resolveLevel=3 -> 8 line segments -> 7 triangles 136 // ... 137 return (1 << resolveLevel) - 1; 138 } 139 PathTessellator(bool infinitySupport,PatchAttribs attribs)140 PathTessellator(bool infinitySupport, PatchAttribs attribs) : fAttribs(attribs) { 141 if (!infinitySupport) { 142 fAttribs |= PatchAttribs::kExplicitCurveType; 143 } 144 } 145 146 PatchAttribs fAttribs; 147 148 // Calculated during prepare(). If using fixed count, this is the resolveLevel to use on our 149 // instanced draws. 2^resolveLevel == numSegments. 150 int fFixedResolveLevel = 0; 151 152 #if SK_GPU_V1 153 friend class PatchWriter; // To access fVertexChunkArray. 154 155 GrVertexChunkArray fVertexChunkArray; 156 157 // If using fixed-count rendering, these are the vertex and index buffers. 158 sk_sp<const GrGpuBuffer> fFixedVertexBuffer; 159 sk_sp<const GrGpuBuffer> fFixedIndexBuffer; 160 #endif 161 }; 162 163 } // namespace skgpu 164 165 #endif // tessellate_PathTessellator_DEFINED 166