| /* |
| * Copyright 2022 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef PathTessellator_DEFINED |
| #define PathTessellator_DEFINED |
| |
| #include "src/core/SkArenaAlloc.h" |
| #include "src/gpu/ganesh/GrGpuBuffer.h" |
| #include "src/gpu/ganesh/GrVertexChunkArray.h" |
| #include "src/gpu/ganesh/geometry/GrInnerFanTriangulator.h" |
| #include "src/gpu/tessellate/FixedCountBufferUtils.h" |
| #include "src/gpu/tessellate/Tessellation.h" |
| |
| class GrMeshDrawTarget; |
| class GrOpFlushState; |
| class SkPath; |
| |
| namespace skgpu::v1 { |
| |
| // Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass, |
| // the caller may or may not be required to draw the path's inner fan separately. |
| class PathTessellator { |
| public: |
| using PatchAttribs = tess::PatchAttribs; |
| |
| struct PathDrawList { |
| PathDrawList(const SkMatrix& pathMatrix, |
| const SkPath& path, |
| const SkPMColor4f& color, |
| PathDrawList* next = nullptr) |
| : fPathMatrix(pathMatrix), fPath(path), fColor(color), fNext(next) {} |
| |
| SkMatrix fPathMatrix; |
| SkPath fPath; |
| SkPMColor4f fColor; |
| PathDrawList* fNext; |
| |
| struct Iter { |
| void operator++() { fHead = fHead->fNext; } |
| bool operator!=(const Iter& b) const { return fHead != b.fHead; } |
| std::tuple<const SkMatrix&, const SkPath&, const SkPMColor4f&> operator*() const { |
| return {fHead->fPathMatrix, fHead->fPath, fHead->fColor}; |
| } |
| const PathDrawList* fHead; |
| }; |
| Iter begin() const { return {this}; } |
| Iter end() const { return {nullptr}; } |
| }; |
| |
| virtual ~PathTessellator() {} |
| |
| PatchAttribs patchAttribs() const { return fAttribs; } |
| |
| // Called before draw(). Prepares GPU buffers containing the geometry to tessellate. |
| virtual void prepare(GrMeshDrawTarget* target, |
| const SkMatrix& shaderMatrix, |
| const PathDrawList& pathDrawList, |
| int totalCombinedPathVerbCnt) = 0; |
| |
| // Issues fixed-count instanced draw calls over the patches. The caller is responsible for |
| // binding its desired pipeline ahead of time. |
| virtual void draw(GrOpFlushState* flushState) const = 0; |
| |
| protected: |
| PathTessellator(bool infinitySupport, PatchAttribs attribs) : fAttribs(attribs) { |
| if (!infinitySupport) { |
| fAttribs |= PatchAttribs::kExplicitCurveType; |
| } |
| } |
| |
| PatchAttribs fAttribs; |
| |
| GrVertexChunkArray fVertexChunkArray; |
| // The max number of vertices that must be drawn to account for the accumulated tessellation |
| // levels of the written patches. |
| int fMaxVertexCount = 0; |
| |
| sk_sp<const GrGpuBuffer> fFixedVertexBuffer; |
| sk_sp<const GrGpuBuffer> fFixedIndexBuffer; |
| }; |
| |
| // Draws an array of "outer curve" patches. Each patch is an independent 4-point curve, representing |
| // either a cubic or a conic. Quadratics are converted to cubics and triangles are converted to |
| // conics with w=Inf. |
| class PathCurveTessellator final : public PathTessellator { |
| public: |
| static PathCurveTessellator* Make(SkArenaAlloc* arena, |
| bool infinitySupport, |
| PatchAttribs attribs = PatchAttribs::kNone) { |
| return arena->make<PathCurveTessellator>(infinitySupport, attribs); |
| } |
| |
| PathCurveTessellator(bool infinitySupport, |
| PatchAttribs attribs = PatchAttribs::kNone) |
| : PathTessellator(infinitySupport, attribs) {} |
| |
| void prepareWithTriangles(GrMeshDrawTarget* target, |
| const SkMatrix& shaderMatrix, |
| GrInnerFanTriangulator::BreadcrumbTriangleList* extraTriangles, |
| const PathDrawList& pathDrawList, |
| int totalCombinedPathVerbCnt); |
| |
| void prepare(GrMeshDrawTarget* target, |
| const SkMatrix& shaderMatrix, |
| const PathDrawList& pathDrawList, |
| int totalCombinedPathVerbCnt) final { |
| this->prepareWithTriangles(target, |
| shaderMatrix, |
| nullptr, // no extra triangles by default |
| pathDrawList, |
| totalCombinedPathVerbCnt); |
| } |
| |
| void draw(GrOpFlushState*) const final; |
| |
| // Draws a 4-point instance for each patch. This method is used for drawing convex hulls over |
| // each cubic with GrFillCubicHullShader. The caller is responsible for binding its desired |
| // pipeline ahead of time. |
| void drawHullInstances(GrOpFlushState*, sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const; |
| }; |
| |
| // Prepares an array of "wedge" patches. A wedge is an independent, 5-point closed contour |
| // consisting of 4 control points plus an anchor point fanning from the center of the curve's |
| // resident contour. A wedge can be either a cubic or a conic. Quadratics and lines are converted to |
| // cubics. Once stencilled, these wedges alone define the complete path. |
| class PathWedgeTessellator final : public PathTessellator { |
| public: |
| static PathWedgeTessellator* Make(SkArenaAlloc* arena, |
| bool infinitySupport, |
| PatchAttribs attribs = PatchAttribs::kNone) { |
| return arena->make<PathWedgeTessellator>(infinitySupport, attribs); |
| } |
| |
| PathWedgeTessellator(bool infinitySupport, PatchAttribs attribs = PatchAttribs::kNone) |
| : PathTessellator(infinitySupport, attribs) { |
| fAttribs |= PatchAttribs::kFanPoint; |
| } |
| |
| void prepare(GrMeshDrawTarget* target, |
| const SkMatrix& shaderMatrix, |
| const PathDrawList& pathDrawList, |
| int totalCombinedPathVerbCnt) final; |
| |
| void draw(GrOpFlushState*) const final; |
| }; |
| |
| } // namespace skgpu::v1 |
| |
| #endif // PathTessellator_DEFINED |