blob: 09135585b2d6de4d5b7c6c091c30c8e7beb61ea7 [file] [log] [blame]
/*
* 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/base/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