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