Use constants for max parametric segments everywhere
There had been plumbing for variable amounts of segments throughout the patch writers and shaders because HW tessellation had to limit it based on what the GPU could handle in its tessellation pipeline. Now that everything just uses the fixed count approach, we can keep it all as constants. I considered letting it remain parameterized in the event we wanted ganesh and graphite to diverge, but figured it was better to have consistent handling of paths. Bug: skia:13263, skia:13056 Change-Id: I351d5d762bdab47e4091b18efbd857ac1e500be4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534567 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
094bcdb9e5
commit
842383b985
@ -163,8 +163,7 @@ void PathCurveTessellator::prepareWithTriangles(
|
||||
int patchPreallocCount = FixedCountCurves::PreallocCount(totalCombinedPathVerbCnt) +
|
||||
(extraTriangles ? extraTriangles->count() : 0);
|
||||
if (patchPreallocCount) {
|
||||
CurveWriter writer{fAttribs, skgpu::kMaxParametricSegments,
|
||||
target, &fVertexChunkArray, patchPreallocCount};
|
||||
CurveWriter writer{fAttribs, target, &fVertexChunkArray, patchPreallocCount};
|
||||
|
||||
// Write out extra space-filling triangles to connect the curve patches with any external
|
||||
// source of geometry (e.g. inner triangulation that handles winding explicitly).
|
||||
@ -237,8 +236,7 @@ void PathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const PathDrawList& pathDrawList,
|
||||
int totalCombinedPathVerbCnt) {
|
||||
if (int patchPreallocCount = FixedCountWedges::PreallocCount(totalCombinedPathVerbCnt)) {
|
||||
WedgeWriter writer{fAttribs, skgpu::kMaxParametricSegments,
|
||||
target, &fVertexChunkArray, patchPreallocCount};
|
||||
WedgeWriter writer{fAttribs, target, &fVertexChunkArray, patchPreallocCount};
|
||||
int resolveLevel = write_wedge_patches(std::move(writer), shaderMatrix, pathDrawList);
|
||||
this->updateResolveLevel(resolveLevel);
|
||||
}
|
||||
|
@ -172,8 +172,7 @@ void StrokeTessellateOp::prePrepareTessellator(GrTessellationShader::ProgramArgs
|
||||
fPatchAttribs,
|
||||
fViewMatrix,
|
||||
this->headStroke(),
|
||||
this->headColor(),
|
||||
StrokeTessellator::kMaxParametricSegments_log2);
|
||||
this->headColor());
|
||||
|
||||
auto fillStencil = &GrUserStencilSettings::kUnused;
|
||||
if (fNeedsStencil) {
|
||||
|
@ -236,8 +236,7 @@ void StrokeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
PathStrokeList* pathStrokeList,
|
||||
int totalCombinedStrokeVerbCnt) {
|
||||
int preallocCount = FixedCountStrokes::PreallocCount(totalCombinedStrokeVerbCnt);
|
||||
FixedCountStrokeWriter patchWriter{fAttribs, kMaxParametricSegments,
|
||||
target, &fVertexChunkArray, preallocCount};
|
||||
FixedCountStrokeWriter patchWriter{fAttribs, target, &fVertexChunkArray, preallocCount};
|
||||
|
||||
fFixedEdgeCount = write_fixed_count_patches(std::move(patchWriter),
|
||||
shaderMatrix,
|
||||
|
@ -27,8 +27,6 @@ namespace skgpu::v1 {
|
||||
// as degenerate triangles.
|
||||
class StrokeTessellator {
|
||||
public:
|
||||
constexpr static int8_t kMaxParametricSegments_log2 =
|
||||
SkNextLog2_portable(kMaxParametricSegments);
|
||||
|
||||
struct PathStrokeList {
|
||||
PathStrokeList(const SkPath& path, const SkStrokeRec& stroke, const SkPMColor4f& color)
|
||||
|
@ -86,13 +86,11 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
|
||||
PatchAttribs attribs,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec& stroke,
|
||||
SkPMColor4f color,
|
||||
int8_t maxParametricSegments_log2)
|
||||
SkPMColor4f color)
|
||||
: GrTessellationShader(kTessellate_GrStrokeTessellationShader_ClassID,
|
||||
GrPrimitiveType::kTriangleStrip, viewMatrix, color)
|
||||
, fPatchAttribs(attribs | PatchAttribs::kJoinControlPoint)
|
||||
, fStroke(stroke)
|
||||
, fMaxParametricSegments_log2(maxParametricSegments_log2) {
|
||||
, fStroke(stroke) {
|
||||
// We should use explicit curve type when, and only when, there isn't infinity support.
|
||||
// Otherwise the GPU can infer curve type based on infinity.
|
||||
SkASSERT(shaderCaps.infinitySupport() != (attribs & PatchAttribs::kExplicitCurveType));
|
||||
@ -606,7 +604,7 @@ void GrStrokeTessellationShader::Impl::emitTessellationCode(
|
||||
// ensures crack-free seaming between instances.
|
||||
tangent = (combinedEdgeID == 0) ? tan0 : tan1;
|
||||
strokeCoord = (combinedEdgeID == 0) ? p0 : p3;
|
||||
})", shader.maxParametricSegments_log2() /* Parametric/radial sort loop count. */);
|
||||
})", skgpu::kMaxFixedResolveLevel /* Parametric/radial sort loop count. */);
|
||||
|
||||
code->append(R"(
|
||||
// At this point 'tangent' is normalized, so the orthogonal vector is also normalized.
|
||||
@ -690,7 +688,6 @@ void GrStrokeTessellationShader::addToKey(const GrShaderCaps&, skgpu::KeyBuilder
|
||||
uint32_t key = (uint32_t)(fPatchAttribs & ~PatchAttribs::kColor);
|
||||
key = (key << 2) | ((keyNeedsJoin) ? fStroke.getJoin() : 0);
|
||||
key = (key << 1) | (uint32_t)fStroke.isHairlineStyle();
|
||||
key = (key << 8) | fMaxParametricSegments_log2;
|
||||
b->add32(key);
|
||||
}
|
||||
|
||||
|
@ -29,14 +29,13 @@ public:
|
||||
|
||||
// 'viewMatrix' is applied to the geometry post tessellation. It cannot have perspective.
|
||||
GrStrokeTessellationShader(const GrShaderCaps&, PatchAttribs, const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec&, SkPMColor4f, int8_t maxParametricSegments_log2);
|
||||
const SkStrokeRec&, SkPMColor4f);
|
||||
|
||||
PatchAttribs attribs() const { return fPatchAttribs; }
|
||||
bool hasDynamicStroke() const { return fPatchAttribs & PatchAttribs::kStrokeParams; }
|
||||
bool hasDynamicColor() const { return fPatchAttribs & PatchAttribs::kColor; }
|
||||
bool hasExplicitCurveType() const { return fPatchAttribs & PatchAttribs::kExplicitCurveType; }
|
||||
const SkStrokeRec& stroke() const { return fStroke;}
|
||||
int8_t maxParametricSegments_log2() const { return fMaxParametricSegments_log2; }
|
||||
|
||||
private:
|
||||
const char* name() const override { return "GrStrokeTessellationShader"; }
|
||||
@ -45,7 +44,6 @@ private:
|
||||
|
||||
const PatchAttribs fPatchAttribs;
|
||||
const SkStrokeRec fStroke;
|
||||
const int8_t fMaxParametricSegments_log2;
|
||||
|
||||
constexpr static int kMaxAttribCount = 6;
|
||||
SkSTArray<kMaxAttribCount, Attribute> fAttribs;
|
||||
|
@ -95,8 +95,7 @@ void TessellateCurvesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
|
||||
FixedCountCurves::IndexBufferSize);
|
||||
|
||||
int patchReserveCount = FixedCountCurves::PreallocCount(path.countVerbs());
|
||||
Writer writer{kAttribs, kMaxParametricSegments,
|
||||
*dw, fixedVertexBuffer, fixedIndexBuffer, patchReserveCount};
|
||||
Writer writer{kAttribs, *dw, fixedVertexBuffer, fixedIndexBuffer, patchReserveCount};
|
||||
|
||||
writer.updatePaintDepthAttrib(geom.order().depthAsFloat());
|
||||
|
||||
|
@ -99,8 +99,7 @@ void TessellateWedgesRenderStep::writeVertices(DrawWriter* dw, const DrawGeometr
|
||||
FixedCountWedges::IndexBufferSize);
|
||||
|
||||
int patchReserveCount = FixedCountWedges::PreallocCount(path.countVerbs());
|
||||
Writer writer{kAttribs, kMaxParametricSegments,
|
||||
*dw, fixedVertexBuffer, fixedIndexBuffer, patchReserveCount};
|
||||
Writer writer{kAttribs, *dw, fixedVertexBuffer, fixedIndexBuffer, patchReserveCount};
|
||||
writer.updatePaintDepthAttrib(geom.order().depthAsFloat());
|
||||
|
||||
// TODO: Is it better to pre-transform on the CPU and only have a matrix uniform to compute
|
||||
|
@ -238,11 +238,8 @@ class PatchWriter {
|
||||
public:
|
||||
template <typename... Args> // forwarded to PatchAllocator
|
||||
PatchWriter(PatchAttribs attribs,
|
||||
int maxTessellationSegments,
|
||||
Args&&... allocArgs)
|
||||
: fAttribs(attribs)
|
||||
, fMaxSegments_pow2(pow2(maxTessellationSegments))
|
||||
, fMaxSegments_pow4(pow2(fMaxSegments_pow2))
|
||||
, fCurrMinSegments_pow4(1.f)
|
||||
, fPatchAllocator(PatchStride(attribs), std::forward<Args>(allocArgs)...)
|
||||
, fJoin(attribs)
|
||||
@ -350,9 +347,8 @@ public:
|
||||
|
||||
// Write a cubic curve with its four control points.
|
||||
AI void writeCubic(float2 p0, float2 p1, float2 p2, float2 p3,
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
float n4 = wangs_formula::cubic_pow4(precision, p0, p1, p2, p3, shaderXform);
|
||||
const VectorXform& shaderXform) {
|
||||
float n4 = wangs_formula::cubic_pow4(kTessellationPrecision, p0, p1, p2, p3, shaderXform);
|
||||
if constexpr (kDiscardFlatCurves) {
|
||||
if (n4 <= 1.f) {
|
||||
// This cubic only needs one segment (e.g. a line) but we're not filling space with
|
||||
@ -364,24 +360,23 @@ public:
|
||||
this->writeCubicPatch(p0, p1, p2, p3);
|
||||
} else {
|
||||
int numPatches = SkScalarCeilToInt(wangs_formula::root4(
|
||||
std::min(n4, pow4(kMaxTessellationSegmentsPerCurve)) / fMaxSegments_pow4));
|
||||
std::min(n4, pow4(kMaxTessellationSegmentsPerCurve)) /
|
||||
pow4(kMaxParametricSegments)));
|
||||
this->chopAndWriteCubics(p0, p1, p2, p3, numPatches);
|
||||
}
|
||||
}
|
||||
AI void writeCubic(const SkPoint pts[4],
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
const VectorXform& shaderXform) {
|
||||
float4 p0p1 = float4::Load(pts);
|
||||
float4 p2p3 = float4::Load(pts + 2);
|
||||
this->writeCubic(p0p1.lo, p0p1.hi, p2p3.lo, p2p3.hi, shaderXform, precision);
|
||||
this->writeCubic(p0p1.lo, p0p1.hi, p2p3.lo, p2p3.hi, shaderXform);
|
||||
}
|
||||
|
||||
// Write a conic curve with three control points and 'w', with the last coord of the last
|
||||
// control point signaling a conic by being set to infinity.
|
||||
AI void writeConic(float2 p0, float2 p1, float2 p2, float w,
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
float n2 = wangs_formula::conic_pow2(precision, p0, p1, p2, w, shaderXform);
|
||||
const VectorXform& shaderXform) {
|
||||
float n2 = wangs_formula::conic_pow2(kTessellationPrecision, p0, p1, p2, w, shaderXform);
|
||||
if constexpr (kDiscardFlatCurves) {
|
||||
if (n2 <= 1.f) {
|
||||
// This conic only needs one segment (e.g. a line) but we're not filling space with
|
||||
@ -393,25 +388,24 @@ public:
|
||||
this->writeConicPatch(p0, p1, p2, w);
|
||||
} else {
|
||||
int numPatches = SkScalarCeilToInt(sqrtf(
|
||||
std::min(n2, pow2(kMaxTessellationSegmentsPerCurve)) / fMaxSegments_pow2));
|
||||
std::min(n2, pow2(kMaxTessellationSegmentsPerCurve)) /
|
||||
pow2(kMaxParametricSegments)));
|
||||
this->chopAndWriteConics(p0, p1, p2, w, numPatches);
|
||||
}
|
||||
}
|
||||
AI void writeConic(const SkPoint pts[3], float w,
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
const VectorXform& shaderXform) {
|
||||
this->writeConic(skvx::bit_pun<float2>(pts[0]),
|
||||
skvx::bit_pun<float2>(pts[1]),
|
||||
skvx::bit_pun<float2>(pts[2]),
|
||||
w, shaderXform, precision);
|
||||
w, shaderXform);
|
||||
}
|
||||
|
||||
// Write a quadratic curve that automatically converts its three control points into an
|
||||
// equivalent cubic.
|
||||
AI void writeQuadratic(float2 p0, float2 p1, float2 p2,
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
float n4 = wangs_formula::quadratic_pow4(precision, p0, p1, p2, shaderXform);
|
||||
const VectorXform& shaderXform) {
|
||||
float n4 = wangs_formula::quadratic_pow4(kTessellationPrecision, p0, p1, p2, shaderXform);
|
||||
if constexpr (kDiscardFlatCurves) {
|
||||
if (n4 <= 1.f) {
|
||||
// This quad only needs one segment (e.g. a line) but we're not filling space with
|
||||
@ -423,17 +417,17 @@ public:
|
||||
this->writeQuadPatch(p0, p1, p2);
|
||||
} else {
|
||||
int numPatches = SkScalarCeilToInt(wangs_formula::root4(
|
||||
std::min(n4, pow4(kMaxTessellationSegmentsPerCurve)) / fMaxSegments_pow4));
|
||||
std::min(n4, pow4(kMaxTessellationSegmentsPerCurve)) /
|
||||
pow4(kMaxParametricSegments)));
|
||||
this->chopAndWriteQuads(p0, p1, p2, numPatches);
|
||||
}
|
||||
}
|
||||
AI void writeQuadratic(const SkPoint pts[3],
|
||||
const VectorXform& shaderXform,
|
||||
float precision = kTessellationPrecision) {
|
||||
const VectorXform& shaderXform) {
|
||||
this->writeQuadratic(skvx::bit_pun<float2>(pts[0]),
|
||||
skvx::bit_pun<float2>(pts[1]),
|
||||
skvx::bit_pun<float2>(pts[2]),
|
||||
shaderXform, precision);
|
||||
shaderXform);
|
||||
}
|
||||
|
||||
// Write a line that is automatically converted into an equivalent cubic.
|
||||
@ -547,11 +541,11 @@ private:
|
||||
|
||||
// Returns true if curve can be written w/o needing to chop (e.g. represented by one instance)
|
||||
bool curveFitsInMaxSegments(float n4) {
|
||||
if (n4 <= fMaxSegments_pow4) {
|
||||
if (n4 <= pow4(kMaxParametricSegments)) {
|
||||
fCurrMinSegments_pow4 = std::max(n4, fCurrMinSegments_pow4);
|
||||
return true;
|
||||
} else {
|
||||
fCurrMinSegments_pow4 = fMaxSegments_pow4;
|
||||
fCurrMinSegments_pow4 = pow4(kMaxParametricSegments);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -695,8 +689,6 @@ private:
|
||||
// attribs enabled (e.g. depending on caps or batching).
|
||||
const PatchAttribs fAttribs;
|
||||
|
||||
const float fMaxSegments_pow2;
|
||||
const float fMaxSegments_pow4;
|
||||
float fCurrMinSegments_pow4;
|
||||
|
||||
PatchAllocator fPatchAllocator;
|
||||
|
Loading…
Reference in New Issue
Block a user