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:
parent
b421a71f37
commit
13fd52e587
@ -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;
|
||||
|
10
gn/gpu.gni
10
gn/gpu.gni
@ -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",
|
||||
]
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
49
src/gpu/tessellate/Tessellation.cpp
Normal file
49
src/gpu/tessellate/Tessellation.cpp
Normal 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
|
59
src/gpu/tessellate/Tessellation.h
Normal file
59
src/gpu/tessellate/Tessellation.h
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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); }
|
||||
|
@ -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"(
|
||||
|
@ -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()) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user