Reland "Create a common Tessellation.h header"

This is a reland of 8a2a020ef4

Original change's description:
> Create a common Tessellation.h header
>
> This header and corresponding implementation will contain common
> definitions and subroutines for tessellation code.
>
> Bug: skia:12524
> Change-Id: Ib29b444177f284acb88a3d5644936674c48c0b89
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/463437
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>

Bug: skia:12524
Change-Id: I874fed63cdab50df841e8a5d25d8c822690b5af8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/464294
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2021-10-27 09:47:26 -06:00 committed by SkCQ
parent b421a71f37
commit 13fd52e587
20 changed files with 200 additions and 115 deletions

View File

@ -218,12 +218,12 @@ DEF_PATH_TESS_BENCH(middle_out_triangulation,
VertexWriter vertexWriter = static_cast<SkPoint*>(fTarget->makeVertexSpace(
sizeof(SkPoint), kNumCubicsInChalkboard, &buffer, &baseVertex));
int numTrianglesWritten;
MiddleOutPolygonTriangulator::WritePathInnerFan(std::move(vertexWriter),
0,
0,
gAlmostIdentity,
fPath,
&numTrianglesWritten);
WritePathMiddleOutInnerFan(std::move(vertexWriter),
0,
0,
gAlmostIdentity,
fPath,
&numTrianglesWritten);
}
using PathStrokeList = StrokeTessellator::PathStrokeList;

View File

@ -324,7 +324,6 @@ skia_gpu_sources = [
# tessellate
"$_src/gpu/tessellate/CullTest.h",
"$_src/gpu/tessellate/MiddleOutPolygonTriangulator.h",
"$_src/gpu/tessellate/PathCurveTessellator.cpp",
"$_src/gpu/tessellate/PathCurveTessellator.h",
"$_src/gpu/tessellate/PathTessellator.h",
@ -826,4 +825,11 @@ skia_native_gpu_sources = [
"$_src/gpu/gl/win/GrGLMakeNativeInterface_win.cpp",
]
skia_shared_gpu_sources = [ "$_src/gpu/BufferWriter.h" ]
skia_shared_gpu_sources = [
"$_src/gpu/BufferWriter.h",
# tessellate
"$_src/gpu/tessellate/MiddleOutPolygonTriangulator.h",
"$_src/gpu/tessellate/Tessellation.cpp",
"$_src/gpu/tessellate/Tessellation.h",
]

View File

@ -64,7 +64,7 @@ SkScalar GrPathUtils::scaleToleranceToSrc(SkScalar devTol,
}
uint32_t GrPathUtils::quadraticPointCount(const SkPoint points[], SkScalar tol) {
return max_bezier_vertices(wangs_formula::quadratic_log2(
return max_bezier_vertices(skgpu::wangs_formula::quadratic_log2(
tolerance_to_wangs_precision(tol), points));
}
@ -94,7 +94,7 @@ uint32_t GrPathUtils::generateQuadraticPoints(const SkPoint& p0,
}
uint32_t GrPathUtils::cubicPointCount(const SkPoint points[], SkScalar tol) {
return max_bezier_vertices(wangs_formula::cubic_log2(
return max_bezier_vertices(skgpu::wangs_formula::cubic_log2(
tolerance_to_wangs_precision(tol), points));
}

View File

@ -16,9 +16,9 @@
#include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/PathCurveTessellator.h"
#include "src/gpu/tessellate/PathWedgeTessellator.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
namespace {
@ -246,13 +246,12 @@ void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
int fanTriangleCount = 0;
for (auto [pathMatrix, path] : *fPathDrawList) {
int numTrianglesWritten;
triangleVertexWriter = MiddleOutPolygonTriangulator::WritePathInnerFan(
std::move(triangleVertexWriter),
0,
0,
pathMatrix,
path,
&numTrianglesWritten);
triangleVertexWriter = WritePathMiddleOutInnerFan(std::move(triangleVertexWriter),
0,
0,
pathMatrix,
path,
&numTrianglesWritten);
fanTriangleCount += numTrianglesWritten;
}
SkASSERT(fanTriangleCount <= maxTrianglesInFans);

View File

@ -9,8 +9,7 @@
#define tessellate_CullTest_DEFINED
#include "include/core/SkMatrix.h"
#include "include/private/SkVx.h"
#include "src/gpu/GrVx.h"
#include "src/gpu/tessellate/Tessellation.h"
namespace skgpu {
@ -98,9 +97,9 @@ public:
private:
// [fMatX, fMatY] maps path coordinates to the float4 [x, y, -x, -y] in device space.
grvx::float4 fMatX;
grvx::float4 fMatY;
grvx::float4 fCullBounds; // [l, t, -r, -b]
float4 fMatX;
float4 fMatY;
float4 fCullBounds; // [l, t, -r, -b]
};
} // namespace skgpu

View File

@ -129,37 +129,6 @@ public:
VertexWriter detachVertexWriter() { return std::move(fVertexWriter); }
static VertexWriter WritePathInnerFan(VertexWriter&& vertexWriter,
int pad32Count,
uint32_t pad32Value,
const PathXform& pathXform,
const SkPath& path,
int* numTrianglesWritten) {
MiddleOutPolygonTriangulator middleOut(std::move(vertexWriter),
pad32Count,
pad32Value,
path.countVerbs());
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
switch (verb) {
SkPoint pt;
case SkPathVerb::kMove:
middleOut.closeAndMove(pathXform.mapPoint(pts[0]));
break;
case SkPathVerb::kLine:
case SkPathVerb::kQuad:
case SkPathVerb::kConic:
case SkPathVerb::kCubic:
pt = pts[SkPathPriv::PtsInIter((unsigned)verb) - 1];
middleOut.pushVertex(pathXform.mapPoint(pt));
break;
case SkPathVerb::kClose:
break;
}
}
*numTrianglesWritten = middleOut.close();
return middleOut.detachVertexWriter();
}
private:
struct StackVertex {
// How many polygon vertices away is this vertex from the previous vertex on the stack?

View File

@ -14,6 +14,7 @@
#include "src/gpu/tessellate/CullTest.h"
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/PathXform.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/WangsFormula.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
@ -25,8 +26,6 @@ namespace skgpu {
namespace {
constexpr static float kPrecision = GrTessellationShader::kLinearizationPrecision;
// Writes out curve patches, chopping as necessary so none require more segments than are
// supported by the hardware.
class CurveWriter {
@ -48,7 +47,9 @@ public:
SK_ALWAYS_INLINE void writeQuadratic(const GrShaderCaps& shaderCaps,
GrVertexChunkBuilder* chunker, const SkPoint p[3]) {
float numSegments_pow4 = wangs_formula::quadratic_pow4(kPrecision, p, fTotalVectorXform);
float numSegments_pow4 = wangs_formula::quadratic_pow4(kTessellationPrecision,
p,
fTotalVectorXform);
if (numSegments_pow4 > fMaxSegments_pow4) {
this->chopAndWriteQuadratic(shaderCaps, chunker, p);
return;
@ -65,7 +66,10 @@ public:
SK_ALWAYS_INLINE void writeConic(const GrShaderCaps& shaderCaps, GrVertexChunkBuilder* chunker,
const SkPoint p[3], float w) {
float numSegments_pow2 = wangs_formula::conic_pow2(kPrecision, p, w, fTotalVectorXform);
float numSegments_pow2 = wangs_formula::conic_pow2(kTessellationPrecision,
p,
w,
fTotalVectorXform);
if (numSegments_pow2 > fMaxSegments_pow2) {
this->chopAndWriteConic(shaderCaps, chunker, {p, w});
return;
@ -83,7 +87,9 @@ public:
SK_ALWAYS_INLINE void writeCubic(const GrShaderCaps& shaderCaps, GrVertexChunkBuilder* chunker,
const SkPoint p[4]) {
float numSegments_pow4 = wangs_formula::cubic_pow4(kPrecision, p, fTotalVectorXform);
float numSegments_pow4 = wangs_formula::cubic_pow4(kTessellationPrecision,
p,
fTotalVectorXform);
if (numSegments_pow4 > fMaxSegments_pow4) {
this->chopAndWriteCubic(shaderCaps, chunker, p);
return;
@ -247,13 +253,12 @@ void PathCurveTessellator::prepare(GrMeshDrawTarget* target,
: sk_bit_cast<uint32_t>(GrTessellationShader::kTriangularConicCurveType);
for (auto [pathMatrix, path] : pathDrawList) {
int numTrianglesWritten;
vertexWriter = MiddleOutPolygonTriangulator::WritePathInnerFan(
std::move(vertexWriter),
pad32Count,
pad32Value,
pathMatrix,
path,
&numTrianglesWritten);
vertexWriter = WritePathMiddleOutInnerFan(std::move(vertexWriter),
pad32Count,
pad32Value,
pathMatrix,
path,
&numTrianglesWritten);
numRemainingTriangles -= numTrianglesWritten;
}
}

View File

@ -12,6 +12,7 @@
#include "src/gpu/geometry/GrPathUtils.h"
#include "src/gpu/tessellate/CullTest.h"
#include "src/gpu/tessellate/PathXform.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/WangsFormula.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
@ -23,8 +24,6 @@ namespace skgpu {
namespace {
constexpr static float kPrecision = GrTessellationShader::kLinearizationPrecision;
// Parses out each contour in a path and tracks the midpoint. Example usage:
//
// SkTPathContourParser parser;
@ -158,7 +157,9 @@ public:
SK_ALWAYS_INLINE void writeQuadraticWedge(const GrShaderCaps& shaderCaps,
const SkPoint p[3],
SkPoint midpoint) {
float numSegments_pow4 = wangs_formula::quadratic_pow4(kPrecision, p, fTotalVectorXform);
float numSegments_pow4 = wangs_formula::quadratic_pow4(kTessellationPrecision,
p,
fTotalVectorXform);
if (numSegments_pow4 > fMaxSegments_pow4) {
this->chopAndWriteQuadraticWedges(shaderCaps, p, midpoint);
return;
@ -176,7 +177,10 @@ public:
const SkPoint p[3],
float w,
SkPoint midpoint) {
float numSegments_pow2 = wangs_formula::conic_pow2(kPrecision, p, w, fTotalVectorXform);
float numSegments_pow2 = wangs_formula::conic_pow2(kTessellationPrecision,
p,
w,
fTotalVectorXform);
if (numSegments_pow2 > fMaxSegments_pow2) {
this->chopAndWriteConicWedges(shaderCaps, {p, w}, midpoint);
return;
@ -194,7 +198,9 @@ public:
SK_ALWAYS_INLINE void writeCubicWedge(const GrShaderCaps& shaderCaps,
const SkPoint p[4],
SkPoint midpoint) {
float numSegments_pow4 = wangs_formula::cubic_pow4(kPrecision, p, fTotalVectorXform);
float numSegments_pow4 = wangs_formula::cubic_pow4(kTessellationPrecision,
p,
fTotalVectorXform);
if (numSegments_pow4 > fMaxSegments_pow4) {
this->chopAndWriteCubicWedges(shaderCaps, p, midpoint);
return;

View File

@ -10,7 +10,7 @@
#include "include/core/SkMatrix.h"
#include "src/gpu/BufferWriter.h"
#include "src/gpu/GrVx.h"
#include "src/gpu/tessellate/Tessellation.h"
namespace skgpu {
@ -21,9 +21,6 @@ namespace skgpu {
// This class stores redundant data, so it is best used only as a stack-allocated object at the
// point of use.
class PathXform {
using float2 = grvx::float2;
using float4 = grvx::float4;
public:
PathXform() = default;
PathXform(const SkMatrix& m) { *this = m; }

View File

@ -11,7 +11,6 @@
#include "src/core/SkPathPriv.h"
#include "src/gpu/GrMeshDrawTarget.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrVx.h"
#include "src/gpu/geometry/GrPathUtils.h"
#include "src/gpu/tessellate/CullTest.h"
#include "src/gpu/tessellate/WangsFormula.h"
@ -43,7 +42,7 @@ float num_combined_segments(float numParametricSegments, float numRadialSegments
return numParametricSegments + numRadialSegments - 1;
}
grvx::float2 pow4(grvx::float2 x) {
float2 pow4(float2 x) {
auto xx = x*x;
return xx*xx;
}
@ -102,8 +101,6 @@ public:
}
void updateTolerances(float numRadialSegmentsPerRadian, SkPaint::Join joinType) {
using grvx::float2;
fNumRadialSegmentsPerRadian = numRadialSegmentsPerRadian;
// Calculate the worst-case numbers of parametric segments our hardware can support for the
@ -675,8 +672,6 @@ private:
};
SK_ALWAYS_INLINE bool cubic_has_cusp(const SkPoint p[4]) {
using grvx::float2;
float2 p0 = skvx::bit_pun<float2>(p[0]);
float2 p1 = skvx::bit_pun<float2>(p[1]);
float2 p2 = skvx::bit_pun<float2>(p[2]);
@ -689,9 +684,9 @@ SK_ALWAYS_INLINE bool cubic_has_cusp(const SkPoint p[4]) {
float2 B = D - C;
float2 A = -3*D + E;
float a = grvx::cross(A, B);
float b = grvx::cross(A, C);
float c = grvx::cross(B, C);
float a = cross(A, B);
float b = cross(A, C);
float c = cross(B, C);
float discr = b*b - 4*a*c;
// If -cuspThreshold <= discr <= cuspThreshold, it means the two roots are within a distance of

View File

@ -8,7 +8,7 @@
#ifndef tessellate_StrokeTessellator_DEFINED
#define tessellate_StrokeTessellator_DEFINED
#include "src/gpu/GrVx.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/shaders/GrStrokeTessellationShader.h"
class GrMeshDrawTarget;
@ -71,9 +71,9 @@ struct StrokeTolerances {
// Decides the number of parametric segments the tessellator adds for each curve. (Uniform
// steps in parametric space.) The tessellator will add enough parametric segments so that,
// once transformed into device space, they never deviate by more than
// 1/TessellationPathRenderer::kLinearizationPrecision pixels from the true curve.
// 1/kTessellationPrecision pixels from the true curve.
constexpr static float CalcParametricPrecision(float matrixMaxScale) {
return matrixMaxScale * GrTessellationShader::kLinearizationPrecision;
return matrixMaxScale * kTessellationPrecision;
}
// Decides the number of radial segments the tessellator adds for each curve. (Uniform steps
// in tangent angle.) The tessellator will add this number of radial segments for each
@ -82,9 +82,9 @@ struct StrokeTolerances {
float strokeWidth) {
return .5f / acosf(std::max(1 - 2 / (parametricPrecision * strokeWidth), -1.f));
}
template<int N> static grvx::vec<N> ApproxNumRadialSegmentsPerRadian(
float parametricPrecision, grvx::vec<N> strokeWidths) {
grvx::vec<N> cosTheta = skvx::max(1 - 2 / (parametricPrecision * strokeWidths), -1);
template<int N> static vec<N> ApproxNumRadialSegmentsPerRadian(float parametricPrecision,
vec<N> strokeWidths) {
vec<N> cosTheta = skvx::max(1 - 2 / (parametricPrecision * strokeWidths), -1);
// Subtract SKVX_APPROX_ACOS_MAX_ERROR so we never account for too few segments.
return .5f / (skvx::approx_acos(cosTheta) - SKVX_APPROX_ACOS_MAX_ERROR);
}
@ -159,7 +159,7 @@ public:
}
private:
grvx::float4 fStrokeWidths{}; // Must be first for alignment purposes.
float4 fStrokeWidths{}; // Must be first for alignment purposes.
float fNumRadialSegmentsPerRadian[4];
const float fParametricPrecision;
int fBufferIdx = 4; // Initialize the buffer as "empty";

View File

@ -0,0 +1,49 @@
/*
* Copyright 2021 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/tessellate/Tessellation.h"
#include "include/core/SkPath.h"
#include "src/core/SkPathPriv.h"
#include "src/gpu/BufferWriter.h"
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
namespace skgpu {
VertexWriter WritePathMiddleOutInnerFan(VertexWriter&& vertexWriter,
int pad32Count,
uint32_t pad32Value,
const SkMatrix& matrix,
const SkPath& path,
int* numTrianglesWritten) {
MiddleOutPolygonTriangulator middleOut(std::move(vertexWriter),
pad32Count,
pad32Value,
path.countVerbs());
PathXform pathXform(matrix);
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
switch (verb) {
SkPoint pt;
case SkPathVerb::kMove:
middleOut.closeAndMove(pathXform.mapPoint(pts[0]));
break;
case SkPathVerb::kLine:
case SkPathVerb::kQuad:
case SkPathVerb::kConic:
case SkPathVerb::kCubic:
pt = pts[SkPathPriv::PtsInIter((unsigned)verb) - 1];
middleOut.pushVertex(pathXform.mapPoint(pt));
break;
case SkPathVerb::kClose:
break;
}
}
*numTrianglesWritten = middleOut.close();
return middleOut.detachVertexWriter();
}
} // namespace skgpu

View File

@ -0,0 +1,59 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef tessellate_Tessellation_DEFINED
#define tessellate_Tessellation_DEFINED
#include "include/core/SkTypes.h"
#include "include/private/SkVx.h"
class SkPath;
class SkMatrix;
namespace skgpu {
struct VertexWriter;
// Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
SK_MAYBE_UNUSED constexpr static float kTessellationPrecision = 4;
// Use familiar type names from SkSL.
template<int N> using vec = skvx::Vec<N, float>;
using float2 = vec<2>;
using float4 = vec<4>;
template<int N> using ivec = skvx::Vec<N, int32_t>;
using int2 = ivec<2>;
using int4 = ivec<4>;
template<int N> using uvec = skvx::Vec<N, uint32_t>;
using uint2 = uvec<2>;
using uint4 = uvec<4>;
SK_MAYBE_UNUSED SK_ALWAYS_INLINE float dot(float2 a, float2 b) {
float2 ab = a*b;
return ab.x() + ab.y();
}
SK_MAYBE_UNUSED SK_ALWAYS_INLINE float cross(float2 a, float2 b) {
float2 x = a * b.yx();
return x[0] - x[1];
}
// Writes out the path's inner fan using a middle-out topology. Writes 3 SkPoints per triangle to
// the VertexWriter. Additionally writes out "pad32Count" repetitions of "pad32Value" after each
// triangle. Set pad32Count to 0 if the triangles are to be tightly packed.
VertexWriter WritePathMiddleOutInnerFan(VertexWriter&&,
int pad32Count,
uint32_t pad32Value,
const SkMatrix&,
const SkPath&,
int* numTrianglesWritten);
} // namespace skgpu
#endif // tessellate_Tessellation_DEFINED

View File

@ -12,7 +12,7 @@
#include "include/core/SkPoint.h"
#include "include/core/SkString.h"
#include "include/private/SkFloatingPoint.h"
#include "src/gpu/GrVx.h"
#include "src/gpu/tessellate/Tessellation.h"
#define AI SK_MAYBE_UNUSED SK_ALWAYS_INLINE
@ -26,7 +26,7 @@
//
// (Goldman, Ron. (2003). 5.6.3 Wang's Formula. "Pyramid Algorithms: A Dynamic Programming Approach
// to Curves and Surfaces for Geometric Modeling". Morgan Kaufmann Publishers.)
namespace wangs_formula {
namespace skgpu::wangs_formula {
// Returns the value by which to multiply length in Wang's formula. (See above.)
template<int Degree> constexpr float length_term(float precision) {
@ -118,10 +118,9 @@ private:
AI float quadratic_pow4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
using grvx::float2, skvx::bit_pun;
float2 p0 = bit_pun<float2>(pts[0]);
float2 p1 = bit_pun<float2>(pts[1]);
float2 p2 = bit_pun<float2>(pts[2]);
float2 p0 = skvx::bit_pun<float2>(pts[0]);
float2 p1 = skvx::bit_pun<float2>(pts[1]);
float2 p2 = skvx::bit_pun<float2>(pts[2]);
float2 v = -2*p1 + p0 + p2;
v = vectorXform(v);
float2 vv = v*v;
@ -148,7 +147,6 @@ AI int quadratic_log2(float precision,
AI float cubic_pow4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
using grvx::float4;
float4 p01 = float4::Load(pts);
float4 p12 = float4::Load(pts + 1);
float4 p23 = float4::Load(pts + 2);
@ -200,10 +198,9 @@ AI float conic_pow2(float precision,
const SkPoint pts[],
float w,
const VectorXform& vectorXform = VectorXform()) {
using grvx::dot, grvx::float2, grvx::float4, skvx::bit_pun;
float2 p0 = vectorXform(bit_pun<float2>(pts[0]));
float2 p1 = vectorXform(bit_pun<float2>(pts[1]));
float2 p2 = vectorXform(bit_pun<float2>(pts[2]));
float2 p0 = vectorXform(skvx::bit_pun<float2>(pts[0]));
float2 p1 = vectorXform(skvx::bit_pun<float2>(pts[1]));
float2 p2 = vectorXform(skvx::bit_pun<float2>(pts[2]));
// Compute center of bounding box in projected space
const float2 C = 0.5f * (skvx::min(skvx::min(p0, p1), p2) + skvx::max(skvx::max(p0, p1), p2));
@ -224,7 +221,7 @@ AI float conic_pow2(float precision,
// Compute numerator and denominator for parametric step size of linearization. Here, the
// epsilon referenced from the cited paper is 1/precision.
const float rp_minus_1 = std::max(0.f, max_len * precision - 1);
const float numer = sqrtf(grvx::dot(dp, dp)) * precision + rp_minus_1 * dw;
const float numer = sqrtf(dot(dp, dp)) * precision + rp_minus_1 * dw;
const float denom = 4 * std::min(w, 1.f);
// Number of segments = sqrt(numer / denom).
@ -309,7 +306,7 @@ SK_MAYBE_UNUSED inline static SkString as_sksl() {
return code;
}
} // namespace wangs_formula
} // namespace skgpu::wangs_formula
#undef AI

View File

@ -8,6 +8,7 @@
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/WangsFormula.h"
namespace {
@ -61,9 +62,10 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareWedgeShader::makeProgr
code.appendf(R"(
#define MAX_TESSELLATION_SEGMENTS %i)", shaderCaps.maxTessellationSegments());
code.appendf(R"(
#define PRECISION %f)", GrTessellationShader::kLinearizationPrecision);
#define PRECISION %f)", skgpu::kTessellationPrecision);
code.append(kSkSLTypeDefs);
code.append(wangs_formula::as_sksl());
code.append(skgpu::wangs_formula::as_sksl());
code.append(R"(
layout(vertices = 1) out;
@ -189,9 +191,9 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareCurveShader::makeProgr
code.appendf(R"(
#define MAX_TESSELLATION_SEGMENTS %i)", shaderCaps.maxTessellationSegments());
code.appendf(R"(
#define PRECISION %f)", GrTessellationShader::kLinearizationPrecision);
#define PRECISION %f)", skgpu::kTessellationPrecision);
code.append(kSkSLTypeDefs);
code.append(wangs_formula::as_sksl());
code.append(skgpu::wangs_formula::as_sksl());
code.append(R"(
layout(vertices = 1) out;

View File

@ -9,6 +9,7 @@
#include "src/core/SkMathPriv.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/WangsFormula.h"
using skgpu::VertexWriter;
@ -70,10 +71,10 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> MiddleOutShader::makeProgramIm
class Impl : public GrPathTessellationShader::Impl {
void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader& shader,
GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
v->defineConstant("PRECISION", GrTessellationShader::kLinearizationPrecision);
v->defineConstant("PRECISION", skgpu::kTessellationPrecision);
v->defineConstant("MAX_FIXED_RESOLVE_LEVEL", (float)kMaxFixedCountResolveLevel);
v->defineConstant("MAX_FIXED_SEGMENTS", (float)kMaxFixedCountSegments);
v->insertFunction(wangs_formula::as_sksl().c_str());
v->insertFunction(skgpu::wangs_formula::as_sksl().c_str());
if (shaderCaps.infinitySupport()) {
v->insertFunction(R"(
bool is_conic_curve() { return isinf(p23.w); }

View File

@ -347,7 +347,7 @@ SkString GrStrokeTessellationShader::HardwareImpl::getTessControlShaderGLSL(
code.appendf("#define NUM_RADIAL_SEGMENTS_PER_RADIAN vsStrokeArgs[0].x\n");
}
code.append(wangs_formula::as_sksl());
code.append(skgpu::wangs_formula::as_sksl());
code.append(kCosineBetweenVectorsFn);
code.append(kMiterExtentFn);
code.append(R"(

View File

@ -27,7 +27,7 @@ void GrStrokeTessellationShader::InstancedImpl::onEmitCode(EmitArgs& args, GrGPA
args.fVertBuilder->insertFunction(kCosineBetweenVectorsFn);
args.fVertBuilder->insertFunction(kMiterExtentFn);
args.fVertBuilder->insertFunction(kUncheckedMixFn);
args.fVertBuilder->insertFunction(wangs_formula::as_sksl().c_str());
args.fVertBuilder->insertFunction(skgpu::wangs_formula::as_sksl().c_str());
// Tessellation control uniforms and/or dynamic attributes.
if (!shader.hasDynamicStroke()) {

View File

@ -17,9 +17,6 @@ class SkArenaAlloc;
// This is a common base class for shaders in the GPU tessellator.
class GrTessellationShader : public GrGeometryProcessor {
public:
// Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
constexpr static float kLinearizationPrecision = 4;
GrTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
const SkPMColor4f& color)

View File

@ -10,6 +10,8 @@
#include "src/gpu/tessellate/WangsFormula.h"
#include "tests/Test.h"
namespace skgpu {
constexpr static float kPrecision = 4; // 1/4 pixel max error.
const SkPoint kSerp[4] = {
@ -516,3 +518,5 @@ DEF_TEST(wangs_formula_conic_vectorXforms, r) {
});
}
}
} // namespace skgpu