Rename tess's pow2 and pow4 suffixes to p2 and p4

Consolidates some other constants, removes the pow2 and pow4 functions
that just computed `x*x` or `x*x*x*x`. Moves the `mix` function into
PatchWriter since that's the only place it's used.

Change-Id: Idaaba40f1007e1f0331ec8d335e6afbe69ddfbad
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/540920
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2022-05-17 09:58:04 -04:00 committed by SkCQ
parent 13980102a5
commit d325dbd05f
11 changed files with 226 additions and 230 deletions

View File

@ -141,7 +141,7 @@ AtlasPathRenderer::AtlasPathRenderer(GrDirectContext* dContext) {
bool AtlasPathRenderer::pathFitsInAtlas(const SkRect& pathDevBounds,
GrAAType fallbackAAType) const {
SkASSERT(fallbackAAType != GrAAType::kNone); // The atlas doesn't support non-AA.
float atlasMaxPathHeight_pow2 = (fallbackAAType == GrAAType::kMSAA)
float atlasMaxPathHeight_p2 = (fallbackAAType == GrAAType::kMSAA)
? kAtlasMaxPathHeightWithMSAAFallback * kAtlasMaxPathHeightWithMSAAFallback
: kAtlasMaxPathHeight * kAtlasMaxPathHeight;
auto [topLeftFloor, botRightCeil] = round_out(pathDevBounds);
@ -151,7 +151,7 @@ bool AtlasPathRenderer::pathFitsInAtlas(const SkRect& pathDevBounds,
// Since we will transpose tall skinny paths, limiting to atlasMaxPathHeight^2 pixels
// guarantees heightInAtlas <= atlasMaxPathHeight, while also allowing paths that are
// very wide and short.
size[0] * size[1] <= atlasMaxPathHeight_pow2;
size[0] * size[1] <= atlasMaxPathHeight_p2;
}
void AtlasPathRenderer::AtlasPathKey::set(const SkMatrix& m, const SkPath& path) {

View File

@ -131,10 +131,10 @@ bool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fShape->asPath(&path);
const SkRect pathDevBounds = args.fViewMatrix->mapRect(args.fShape->bounds());
float n4 = wangs_formula::worst_case_cubic_pow4(tess::kPrecision,
pathDevBounds.width(),
pathDevBounds.height());
if (n4 > pow4(tess::kMaxSegmentsPerCurve)) {
float n4 = wangs_formula::worst_case_cubic_p4(tess::kPrecision,
pathDevBounds.width(),
pathDevBounds.height());
if (n4 > tess::kMaxSegmentsPerCurve_p4) {
// The path is extremely large. Pre-chop its curves to keep the number of tessellation
// segments tractable. This will also flatten curves that fall completely outside the
// viewport.
@ -223,10 +223,10 @@ void TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
SkPath path;
args.fShape->asPath(&path);
float n4 = wangs_formula::worst_case_cubic_pow4(tess::kPrecision,
pathDevBounds.width(),
pathDevBounds.height());
if (n4 > pow4(tess::kMaxSegmentsPerCurve)) {
float n4 = wangs_formula::worst_case_cubic_p4(tess::kPrecision,
pathDevBounds.width(),
pathDevBounds.height());
if (n4 > tess::kMaxSegmentsPerCurve_p4) {
SkRect viewport = SkRect::Make(*args.fClipConservativeBounds);
path = PreChopPathCurves(tess::kPrecision, path, *args.fViewMatrix, viewport);
}

View File

@ -26,27 +26,27 @@ const GrPipeline* GrTessellationShader::MakePipeline(const ProgramArgs& args,
const char* GrTessellationShader::WangsFormulaSkSL() {
static_assert(skgpu::wangs_formula::length_term<3>(1) == 0.75);
static_assert(skgpu::wangs_formula::length_term_pow2<3>(1) == 0.5625);
static_assert(skgpu::wangs_formula::length_term_p2<3>(1) == 0.5625);
return R"(
// Returns the length squared of the largest forward difference from Wang's cubic formula.
float wangs_formula_max_fdiff_pow2(float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float wangs_formula_max_fdiff_p2(float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float2 d0 = matrix * (fma(float2(-2), p1, p2) + p0);
float2 d1 = matrix * (fma(float2(-2), p2, p3) + p1);
return max(dot(d0,d0), dot(d1,d1));
}
float wangs_formula_cubic(float _precision_, float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float m = wangs_formula_max_fdiff_pow2(p0, p1, p2, p3, matrix);
float m = wangs_formula_max_fdiff_p2(p0, p1, p2, p3, matrix);
return max(ceil(sqrt(0.75 * _precision_ * sqrt(m))), 1.0);
}
float wangs_formula_cubic_log2(float _precision_, float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float m = wangs_formula_max_fdiff_pow2(p0, p1, p2, p3, matrix);
float m = wangs_formula_max_fdiff_p2(p0, p1, p2, p3, matrix);
return ceil(log2(max(0.5625 * _precision_ * _precision_ * m, 1.0)) * .25);
}
float wangs_formula_conic_pow2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float wangs_formula_conic_p2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
// Translate the bounding box center to the origin.
float2 C = (min(min(p0, p1), p2) + max(max(p0, p1), p2)) * 0.5;
p0 -= C;
@ -69,11 +69,11 @@ float wangs_formula_conic_pow2(float _precision_, float2 p0, float2 p1, float2 p
return numer/denom;
}
float wangs_formula_conic(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float n2 = wangs_formula_conic_pow2(_precision_, p0, p1, p2, w);
float n2 = wangs_formula_conic_p2(_precision_, p0, p1, p2, w);
return max(ceil(sqrt(n2)), 1.0);
}
float wangs_formula_conic_log2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float n2 = wangs_formula_conic_pow2(_precision_, p0, p1, p2, w);
float n2 = wangs_formula_conic_p2(_precision_, p0, p1, p2, w);
return ceil(log2(max(n2, 1.0)) * .5);
})";
}

View File

@ -33,14 +33,14 @@ namespace skgpu::tess {
*/
class LinearTolerances {
public:
float numParametricSegments_pow4() const { return fNumParametricSegments_pow4; }
float numParametricSegments_p4() const { return fNumParametricSegments_p4; }
float numRadialSegmentsPerRadian() const { return fNumRadialSegmentsPerRadian; }
int numEdgesInJoins() const { return fEdgesInJoins; }
// Fast log2 of minimum required # of segments per tracked Wang's formula calculations.
int requiredResolveLevel() const {
// log16(n^4) == log2(n)
return wangs_formula::nextlog16(fNumParametricSegments_pow4);
return wangs_formula::nextlog16(fNumParametricSegments_p4);
}
int requiredStrokeEdges() const {
@ -49,7 +49,7 @@ public:
std::max(SkScalarCeilToInt(fNumRadialSegmentsPerRadian * SK_ScalarPI), 1);
int maxParametricSegmentsInStroke =
SkScalarCeilToInt(wangs_formula::root4(fNumParametricSegments_pow4));
SkScalarCeilToInt(wangs_formula::root4(fNumParametricSegments_p4));
SkASSERT(maxParametricSegmentsInStroke >= 1);
// Now calculate the maximum number of edges we will need in the stroke portion of the
@ -79,7 +79,7 @@ public:
void setParametricSegments(float n4) {
SkASSERT(n4 >= 0.f);
fNumParametricSegments_pow4 = n4;
fNumParametricSegments_p4 = n4;
}
void setStroke(const StrokeParams& strokeParams, float maxScale) {
@ -103,8 +103,8 @@ public:
}
void accumulate(const LinearTolerances& tolerances) {
if (tolerances.fNumParametricSegments_pow4 > fNumParametricSegments_pow4) {
fNumParametricSegments_pow4 = tolerances.fNumParametricSegments_pow4;
if (tolerances.fNumParametricSegments_p4 > fNumParametricSegments_p4) {
fNumParametricSegments_p4 = tolerances.fNumParametricSegments_p4;
}
if (tolerances.fNumRadialSegmentsPerRadian > fNumRadialSegmentsPerRadian) {
fNumRadialSegmentsPerRadian = tolerances.fNumRadialSegmentsPerRadian;
@ -116,7 +116,7 @@ public:
private:
// Used for both fills and strokes, always at least one parametric segment
float fNumParametricSegments_pow4 = 1.f;
float fNumParametricSegments_p4 = 1.f;
// Used for strokes, adding additional segments along the curve to account for its rotation
// TODO: Currently we assume the worst case 180 degree rotation for any curve, but tracking
// max(radialSegments * patch curvature) would be tighter. This would require computing

View File

@ -166,17 +166,17 @@ VertexWriter& operator<<(VertexWriter& w, const AttribValue<A, T, Required, Opti
// Stores state and deferred patch data when TrackJoinControlPoints is used for a PatchWriter.
template <size_t Stride>
struct PatchStorage {
float fN_pow4 = -1.f; // The parametric segment value to restore on LinearTolerances
float fN_p4 = -1.f; // The parametric segment value to restore on LinearTolerances
bool fMustDefer = true; // True means next patch must be deferred
// Holds an entire patch, except with an undefined join control point.
char fData[Stride];
bool hasPending() const {
return fN_pow4 >= 0.f;
return fN_p4 >= 0.f;
}
void reset() {
fN_pow4 = -1.f;
fN_p4 = -1.f;
fMustDefer = true;
}
};
@ -298,7 +298,7 @@ public:
// Assuming that the stroke parameters aren't changing within a contour, we only have
// to set the parametric segments in order to recover the LinearTolerances state at the
// time the deferred patch was recorded.
fTolerances.setParametricSegments(fDeferredPatch.fN_pow4);
fTolerances.setParametricSegments(fDeferredPatch.fN_p4);
if (VertexWriter vw = fPatchAllocator.append(fTolerances)) {
vw << VertexWriter::Array<char>(fDeferredPatch.fData, fPatchAllocator.stride());
}
@ -367,7 +367,7 @@ public:
// Write a cubic curve with its four control points.
AI void writeCubic(float2 p0, float2 p1, float2 p2, float2 p3) {
float n4 = wangs_formula::cubic_pow4(kPrecision, p0, p1, p2, p3, fApproxTransform);
float n4 = wangs_formula::cubic_p4(kPrecision, p0, p1, p2, p3, fApproxTransform);
if constexpr (kDiscardFlatCurves) {
if (n4 <= 1.f) {
// This cubic only needs one segment (e.g. a line) but we're not filling space with
@ -390,7 +390,7 @@ public:
// 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) {
float n2 = wangs_formula::conic_pow2(kPrecision, p0, p1, p2, w, fApproxTransform);
float n2 = wangs_formula::conic_p2(kPrecision, p0, p1, p2, w, fApproxTransform);
if constexpr (kDiscardFlatCurves) {
if (n2 <= 1.f) {
// This conic only needs one segment (e.g. a line) but we're not filling space with
@ -414,7 +414,7 @@ public:
// Write a quadratic curve that automatically converts its three control points into an
// equivalent cubic.
AI void writeQuadratic(float2 p0, float2 p1, float2 p2) {
float n4 = wangs_formula::quadratic_pow4(kPrecision, p0, p1, p2, fApproxTransform);
float n4 = wangs_formula::quadratic_p4(kPrecision, p0, p1, p2, fApproxTransform);
if constexpr (kDiscardFlatCurves) {
if (n4 <= 1.f) {
// This quad only needs one segment (e.g. a line) but we're not filling space with
@ -460,8 +460,8 @@ public:
AI void writeTriangle(float2 p0, float2 p1, float2 p2) {
// No chopping needed, the max supported segment count should always support 2 lines
// (which form a triangle when implicitly closed).
static constexpr float kTriangleSegments_pow4 = 2.f * 2.f * 2.f * 2.f;
fTolerances.setParametricSegments(kTriangleSegments_pow4);
static constexpr float kTriangleSegments_p4 = 2.f * 2.f * 2.f * 2.f;
fTolerances.setParametricSegments(kTriangleSegments_p4);
this->writePatch(p0, p1, p2, {SK_FloatInfinity, SK_FloatInfinity},
kTriangularConicCurveType);
}
@ -499,7 +499,7 @@ private:
SkASSERT(fPatchAllocator.stride() <= kMaxStride);
// Save the computed parametric segment tolerance value so that we can pass that to
// the PatchAllocator when flushing the deferred patch.
fDeferredPatch.fN_pow4 = fTolerances.numParametricSegments_pow4();
fDeferredPatch.fN_p4 = fTolerances.numParametricSegments_p4();
return {fDeferredPatch.fData, fPatchAllocator.stride()};
}
}
@ -546,19 +546,27 @@ private:
}
int accountForCurve(float n4) {
if (n4 <= pow4(kMaxParametricSegments)) {
if (n4 <= kMaxParametricSegments_p4) {
// Record n^4 and return 0 to signal no chopping
fTolerances.setParametricSegments(n4);
return 0;
} else {
// Clamp to max allowed segmentation for a patch and return required number of chops
// to achieve visual correctness.
fTolerances.setParametricSegments(pow4(kMaxParametricSegments));
return SkScalarCeilToInt(wangs_formula::root4(std::min(n4, pow4(kMaxSegmentsPerCurve)) /
pow4(kMaxParametricSegments)));
fTolerances.setParametricSegments(kMaxParametricSegments_p4);
return SkScalarCeilToInt(wangs_formula::root4(std::min(n4, kMaxSegmentsPerCurve_p4) /
kMaxParametricSegments_p4));
}
}
// This does not return b when t==1, but it otherwise seems to get better precision than
// "a*(1 - t) + b*t" for things like chopping cubics on exact cusp points.
// The responsibility falls on the caller to check that t != 1 before calling.
static AI float4 mix(float4 a, float4 b, float4 T) {
SkASSERT(all((0 <= T) & (T < 1)));
return (b - a)*T + a;
}
// Helpers that chop the curve type into 'numPatches' parametrically uniform curves. It is
// assumed that 'numPatches' is calculated such that the resulting curves require the maximum
// number of segments to draw appropriately (since the original presumably needed even more).

View File

@ -61,8 +61,8 @@ public:
if (!fCullTest.areVisible3(p)) {
fPath.lineTo(p[2]);
} else {
float n4 = wangs_formula::quadratic_pow4(fTessellationPrecision, p, fVectorXform);
if (n4 > pow4(kMaxSegmentsPerCurve) && numChops < kMaxChopsPerCurve) {
float n4 = wangs_formula::quadratic_p4(fTessellationPrecision, p, fVectorXform);
if (n4 > kMaxSegmentsPerCurve_p4 && numChops < kMaxChopsPerCurve) {
SkPoint chops[5];
SkChopQuadAtHalf(p, chops);
fPointStack.pop_back_n(3);
@ -90,8 +90,8 @@ public:
if (!fCullTest.areVisible3(p)) {
fPath.lineTo(p[2]);
} else {
float n2 = wangs_formula::conic_pow2(fTessellationPrecision, p, w, fVectorXform);
if (n2 > pow2(kMaxSegmentsPerCurve) && numChops < kMaxChopsPerCurve) {
float n2 = wangs_formula::conic_p2(fTessellationPrecision, p, w, fVectorXform);
if (n2 > kMaxSegmentsPerCurve_p2 && numChops < kMaxChopsPerCurve) {
SkConic chops[2];
if (!SkConic(p,w).chopAt(.5, chops)) {
SkPoint line[2] = {p[0], p[2]};
@ -125,8 +125,8 @@ public:
if (!fCullTest.areVisible4(p)) {
fPath.lineTo(p[3]);
} else {
float n4 = wangs_formula::cubic_pow4(fTessellationPrecision, p, fVectorXform);
if (n4 > pow4(kMaxSegmentsPerCurve) && numChops < kMaxChopsPerCurve) {
float n4 = wangs_formula::cubic_p4(fTessellationPrecision, p, fVectorXform);
if (n4 > kMaxSegmentsPerCurve_p4 && numChops < kMaxChopsPerCurve) {
SkPoint chops[7];
SkChopCubicAtHalf(p, chops);
fPointStack.pop_back_n(4);

View File

@ -45,23 +45,6 @@ AI float cross(float2 a, float2 b) {
return x[0] - x[1];
}
// This does not return b when t==1, but it otherwise seems to get better precision than
// "a*(1 - t) + b*t" for things like chopping cubics on exact cusp points.
// The responsibility falls on the caller to check that t != 1 before calling.
template<int N>
AI vec<N> mix(vec<N> a, vec<N> b, vec<N> T) {
SkASSERT(all((0 <= T) & (T < 1)));
return (b - a)*T + a;
}
template<int N>
AI vec<N> mix(vec<N> a, vec<N> b, float T) {
return mix(a, b, vec<N>(T));
}
AI constexpr float pow2(float x) { return x*x; }
AI constexpr float pow4(float x) { return pow2(x*x); }
#undef AI
} // namespace skgpu
@ -81,6 +64,9 @@ constexpr static int kMaxResolveLevel = 5;
// path filling algorithms snap their dynamic vertex counts to powers-of-two, whereas the stroking
// algorithm does not.
constexpr static int kMaxParametricSegments = 1 << kMaxResolveLevel;
constexpr static int kMaxParametricSegments_p2 = kMaxParametricSegments * kMaxParametricSegments;
constexpr static int kMaxParametricSegments_p4 = kMaxParametricSegments_p2 *
kMaxParametricSegments_p2;
// Don't tessellate paths that might have an individual curve that requires more than 1024 segments.
// (See wangs_formula::worst_case_cubic). If this is the case, call "PreChopPathCurves" first.
@ -88,6 +74,8 @@ constexpr static int kMaxParametricSegments = 1 << kMaxResolveLevel;
// kMaxTessellationSegmentsPerCurve is handled automatically by PatchWriter. It differs from
// PreChopPathCurves in that it does no culling of offscreen chopped paths.
constexpr static float kMaxSegmentsPerCurve = 1024;
constexpr static float kMaxSegmentsPerCurve_p2 = kMaxSegmentsPerCurve * kMaxSegmentsPerCurve;
constexpr static float kMaxSegmentsPerCurve_p4 = kMaxSegmentsPerCurve_p2 * kMaxSegmentsPerCurve_p2;
// Returns a new path, equivalent to 'path' within the given viewport, whose verbs can all be drawn
// with 'maxSegments' tessellation segments or fewer, while staying within '1/tessellationPrecision'

View File

@ -32,7 +32,7 @@ namespace skgpu::wangs_formula {
template<int Degree> constexpr float length_term(float precision) {
return (Degree * (Degree - 1) / 8.f) * precision;
}
template<int Degree> constexpr float length_term_pow2(float precision) {
template<int Degree> constexpr float length_term_p2(float precision) {
return ((Degree * Degree) * ((Degree - 1) * (Degree - 1)) / 64.f) * (precision * precision);
}
@ -113,29 +113,29 @@ private:
};
// Returns Wang's formula, raised to the 4th power, specialized for a quadratic curve.
AI float quadratic_pow4(float precision,
float2 p0, float2 p1, float2 p2,
const VectorXform& vectorXform = VectorXform()) {
AI float quadratic_p4(float precision,
float2 p0, float2 p1, float2 p2,
const VectorXform& vectorXform = VectorXform()) {
float2 v = -2*p1 + p0 + p2;
v = vectorXform(v);
float2 vv = v*v;
return (vv[0] + vv[1]) * length_term_pow2<2>(precision);
return (vv[0] + vv[1]) * length_term_p2<2>(precision);
}
AI float quadratic_pow4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return quadratic_pow4(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
vectorXform);
AI float quadratic_p4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return quadratic_p4(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
vectorXform);
}
// Returns Wang's formula specialized for a quadratic curve.
AI float quadratic(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return root4(quadratic_pow4(precision, pts, vectorXform));
return root4(quadratic_p4(precision, pts, vectorXform));
}
// Returns the log2 value of Wang's formula specialized for a quadratic curve, rounded up to the
@ -144,37 +144,37 @@ AI int quadratic_log2(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
// nextlog16(x) == ceil(log2(sqrt(sqrt(x))))
return nextlog16(quadratic_pow4(precision, pts, vectorXform));
return nextlog16(quadratic_p4(precision, pts, vectorXform));
}
// Returns Wang's formula, raised to the 4th power, specialized for a cubic curve.
AI float cubic_pow4(float precision,
float2 p0, float2 p1, float2 p2, float2 p3,
const VectorXform& vectorXform = VectorXform()) {
AI float cubic_p4(float precision,
float2 p0, float2 p1, float2 p2, float2 p3,
const VectorXform& vectorXform = VectorXform()) {
float4 p01{p0, p1};
float4 p12{p1, p2};
float4 p23{p2, p3};
float4 v = -2*p12 + p01 + p23;
v = vectorXform(v);
float4 vv = v*v;
return std::max(vv[0] + vv[1], vv[2] + vv[3]) * length_term_pow2<3>(precision);
return std::max(vv[0] + vv[1], vv[2] + vv[3]) * length_term_p2<3>(precision);
}
AI float cubic_pow4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return cubic_pow4(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
skvx::bit_pun<float2>(pts[3]),
vectorXform);
AI float cubic_p4(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return cubic_p4(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
skvx::bit_pun<float2>(pts[3]),
vectorXform);
}
// Returns Wang's formula specialized for a cubic curve.
AI float cubic(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
return root4(cubic_pow4(precision, pts, vectorXform));
return root4(cubic_p4(precision, pts, vectorXform));
}
// Returns the log2 value of Wang's formula specialized for a cubic curve, rounded up to the next
@ -183,29 +183,29 @@ AI int cubic_log2(float precision,
const SkPoint pts[],
const VectorXform& vectorXform = VectorXform()) {
// nextlog16(x) == ceil(log2(sqrt(sqrt(x))))
return nextlog16(cubic_pow4(precision, pts, vectorXform));
return nextlog16(cubic_p4(precision, pts, vectorXform));
}
// Returns the maximum number of line segments a cubic with the given device-space bounding box size
// would ever need to be divided into, raised to the 4th power. This is simply a special case of the
// cubic formula where we maximize its value by placing control points on specific corners of the
// bounding box.
AI float worst_case_cubic_pow4(float precision, float devWidth, float devHeight) {
float kk = length_term_pow2<3>(precision);
AI float worst_case_cubic_p4(float precision, float devWidth, float devHeight) {
float kk = length_term_p2<3>(precision);
return 4*kk * (devWidth * devWidth + devHeight * devHeight);
}
// Returns the maximum number of line segments a cubic with the given device-space bounding box size
// would ever need to be divided into.
AI float worst_case_cubic(float precision, float devWidth, float devHeight) {
return root4(worst_case_cubic_pow4(precision, devWidth, devHeight));
return root4(worst_case_cubic_p4(precision, devWidth, devHeight));
}
// Returns the maximum log2 number of line segments a cubic with the given device-space bounding box
// size would ever need to be divided into.
AI int worst_case_cubic_log2(float precision, float devWidth, float devHeight) {
// nextlog16(x) == ceil(log2(sqrt(sqrt(x))))
return nextlog16(worst_case_cubic_pow4(precision, devWidth, devHeight));
return nextlog16(worst_case_cubic_p4(precision, devWidth, devHeight));
}
// Returns Wang's formula specialized for a conic curve, raised to the second power.
@ -214,10 +214,10 @@ AI int worst_case_cubic_log2(float precision, float devWidth, float devHeight) {
// This is not actually due to Wang, but is an analogue from (Theorem 3, corollary 1):
// J. Zheng, T. Sederberg. "Estimating Tessellation Parameter Intervals for
// Rational Curves and Surfaces." ACM Transactions on Graphics 19(1). 2000.
AI float conic_pow2(float precision,
float2 p0, float2 p1, float2 p2,
float w,
const VectorXform& vectorXform = VectorXform()) {
AI float conic_p2(float precision,
float2 p0, float2 p1, float2 p2,
float w,
const VectorXform& vectorXform = VectorXform()) {
p0 = vectorXform(p0);
p1 = vectorXform(p1);
p2 = vectorXform(p2);
@ -249,16 +249,16 @@ AI float conic_pow2(float precision,
// If not, the number of segments is (tmax - tmin) / sqrt(denom / numer).
return numer / denom;
}
AI float conic_pow2(float precision,
const SkPoint pts[],
float w,
const VectorXform& vectorXform = VectorXform()) {
return conic_pow2(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
w,
vectorXform);
AI float conic_p2(float precision,
const SkPoint pts[],
float w,
const VectorXform& vectorXform = VectorXform()) {
return conic_p2(precision,
skvx::bit_pun<float2>(pts[0]),
skvx::bit_pun<float2>(pts[1]),
skvx::bit_pun<float2>(pts[2]),
w,
vectorXform);
}
// Returns the value of Wang's formula specialized for a conic curve.
@ -266,7 +266,7 @@ AI float conic(float tolerance,
const SkPoint pts[],
float w,
const VectorXform& vectorXform = VectorXform()) {
return sqrtf(conic_pow2(tolerance, pts, w, vectorXform));
return sqrtf(conic_p2(tolerance, pts, w, vectorXform));
}
// Returns the log2 value of Wang's formula specialized for a conic curve, rounded up to the next
@ -276,7 +276,7 @@ AI int conic_log2(float tolerance,
float w,
const VectorXform& vectorXform = VectorXform()) {
// nextlog4(x) == ceil(log2(sqrt(x)))
return nextlog4(conic_pow2(tolerance, pts, w, vectorXform));
return nextlog4(conic_p2(tolerance, pts, w, vectorXform));
}
} // namespace skgpu::wangs_formula

View File

@ -1,4 +1,4 @@
static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,12,2,
7,36,68,101,103,114,101,101,
5,102,108,111,97,116,
10,36,80,114,101,99,105,115,105,111,110,
@ -11,12 +11,12 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,112,51,
6,109,97,116,114,105,120,
8,102,108,111,97,116,50,120,50,
28,119,97,110,103,115,95,102,111,114,109,117,108,97,95,109,97,120,95,102,100,105,102,102,95,112,111,119,50,
26,119,97,110,103,115,95,102,111,114,109,117,108,97,95,109,97,120,95,102,100,105,102,102,95,112,50,
11,95,112,114,101,99,105,115,105,111,110,95,
19,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,117,98,105,99,
24,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,117,98,105,99,95,108,111,103,50,
1,119,
24,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,111,110,105,99,95,112,111,119,50,
22,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,111,110,105,99,95,112,50,
19,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,111,110,105,99,
24,119,97,110,103,115,95,102,111,114,109,117,108,97,95,99,111,110,105,99,95,108,111,103,50,
12,114,101,115,111,108,118,101,76,101,118,101,108,
@ -101,7 +101,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,90,0,5,5,0,6,0,7,0,8,0,9,0,
51,255,255,10,0,
55,11,0,
17,119,0,
17,117,0,
51,255,255,10,0,3,
55,12,0,
17,55,0,
@ -119,10 +119,10 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,74,0,
51,255,255,81,0,3,
28,17,0,
17,131,0,6,11,0,12,0,13,0,14,0,15,0,16,0,
17,129,0,6,11,0,12,0,13,0,14,0,15,0,16,0,
51,255,255,10,0,
55,18,0,
17,119,0,
17,117,0,
51,255,255,10,0,3,
55,19,0,
17,55,0,
@ -140,10 +140,10 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,74,0,
51,255,255,81,0,3,
28,24,0,
17,151,0,6,18,0,19,0,20,0,21,0,22,0,23,0,
17,149,0,6,18,0,19,0,20,0,21,0,22,0,23,0,
51,255,255,10,0,
55,25,0,
17,119,0,
17,117,0,
51,255,255,10,0,3,
55,26,0,
17,55,0,
@ -155,13 +155,13 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,68,0,
51,255,255,58,0,3,
55,29,0,
17,176,0,
17,174,0,
51,255,255,10,0,3,
28,30,0,
17,178,0,5,25,0,26,0,27,0,28,0,29,0,
17,176,0,5,25,0,26,0,27,0,28,0,29,0,
51,255,255,10,0,
55,31,0,
17,119,0,
17,117,0,
51,255,255,10,0,3,
55,32,0,
17,55,0,
@ -173,13 +173,13 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,68,0,
51,255,255,58,0,3,
55,35,0,
17,176,0,
17,174,0,
51,255,255,10,0,3,
28,36,0,
17,203,0,5,31,0,32,0,33,0,34,0,35,0,
17,199,0,5,31,0,32,0,33,0,34,0,35,0,
51,255,255,10,0,
55,37,0,
17,119,0,
17,117,0,
51,255,255,10,0,3,
55,38,0,
17,55,0,
@ -191,43 +191,43 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,68,0,
51,255,255,58,0,3,
55,41,0,
17,176,0,
17,174,0,
51,255,255,10,0,3,
28,42,0,
17,223,0,5,37,0,38,0,39,0,40,0,41,0,
17,219,0,5,37,0,38,0,39,0,40,0,41,0,
51,255,255,10,0,
55,43,0,
17,248,0,
17,244,0,
51,255,255,10,0,3,
55,44,0,
17,5,1,
17,1,1,
51,255,255,10,0,3,
55,45,0,
17,23,1,
51,255,255,27,1,3,
17,19,1,
51,255,255,23,1,3,
55,46,0,
17,34,1,
51,255,255,27,1,3,
17,30,1,
51,255,255,23,1,3,
28,47,0,
17,38,1,4,43,0,44,0,45,0,46,0,
17,34,1,4,43,0,44,0,45,0,46,0,
51,255,255,58,0,
55,48,0,
17,248,0,
17,244,0,
51,255,255,10,0,3,
55,49,0,
17,5,1,
17,1,1,
51,255,255,10,0,3,
55,50,0,
17,23,1,
51,255,255,27,1,3,
17,19,1,
51,255,255,23,1,3,
55,51,0,
17,34,1,
51,255,255,27,1,3,
17,30,1,
51,255,255,23,1,3,
55,52,0,
17,55,1,
17,51,1,
51,255,255,58,0,3,
28,53,0,
17,70,1,5,48,0,49,0,50,0,51,0,52,0,
17,66,1,5,48,0,49,0,50,0,51,0,52,0,
51,255,255,58,0,12,0,
0,0,
2,0,
@ -266,10 +266,10 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,2,0,
55,54,0,
17,87,1,
17,83,1,
51,255,255,58,0,2,
55,55,0,
17,90,1,
17,86,1,
51,255,255,58,0,2,2,0,
0,0,
1,0,3,
@ -279,7 +279,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,9,0,0,2,
1,
27,
51,255,255,58,0,255,255,93,1,3,
51,255,255,58,0,255,255,89,1,3,
13,
51,255,255,58,0,1,
25,
@ -293,7 +293,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,9,0,0,2,
1,
27,
51,255,255,58,0,255,255,93,1,3,
51,255,255,58,0,255,255,89,1,3,
13,
51,255,255,58,0,1,
25,
@ -303,20 +303,20 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,6,0,0,
44,
27,
51,255,255,10,0,255,255,93,1,2,
27,
51,255,255,10,0,255,255,97,1,2,
27,
51,255,255,10,0,255,255,101,1,2,
57,54,0,0,
57,54,0,0,
27,
51,255,255,10,0,255,255,101,1,2,
51,255,255,10,0,255,255,97,1,2,
57,55,0,0,
57,55,0,0,1,
29,17,0,
2,
52,1,1,0,
55,56,0,
17,105,1,
17,101,1,
51,255,255,10,0,2,1,0,
0,0,2,
56,56,0,
@ -330,17 +330,17 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,16,0,0,
44,
27,
51,255,255,10,0,255,255,97,1,2,
51,255,255,10,0,255,255,93,1,2,
27,
51,255,255,10,0,255,255,107,1,1,
51,255,255,10,0,255,255,103,1,1,
27,
51,255,255,10,0,255,255,112,1,1,
51,255,255,10,0,255,255,108,1,1,
1,
1,
57,3,0,0,2,
57,11,0,0,2,
27,
51,255,255,10,0,255,255,112,1,1,
51,255,255,10,0,255,255,108,1,1,
57,56,0,0,
25,
51,255,255,10,0,0,0,128,63,1,
@ -348,7 +348,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,1,0,
55,57,0,
17,105,1,
17,101,1,
51,255,255,10,0,2,1,0,
0,0,2,
56,57,0,
@ -362,12 +362,12 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,23,0,0,
44,
27,
51,255,255,10,0,255,255,107,1,1,
51,255,255,10,0,255,255,103,1,1,
1,
27,
51,255,255,10,0,255,255,117,1,1,
51,255,255,10,0,255,255,113,1,1,
27,
51,255,255,10,0,255,255,97,1,2,
51,255,255,10,0,255,255,93,1,2,
1,
1,
1,
@ -383,25 +383,25 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,7,0,
55,58,0,
17,122,1,
17,118,1,
51,255,255,58,0,2,
55,59,0,
17,105,1,
17,101,1,
51,255,255,10,0,2,
55,60,0,
17,124,1,
17,120,1,
51,255,255,58,0,2,
55,61,0,
17,127,1,
17,123,1,
51,255,255,10,0,2,
55,62,0,
17,130,1,
17,126,1,
51,255,255,10,0,2,
55,63,0,
17,141,1,
17,137,1,
51,255,255,10,0,2,
55,64,0,
17,147,1,
17,143,1,
51,255,255,10,0,2,7,0,
0,0,
6,0,
@ -415,16 +415,16 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
1,
1,
27,
51,255,255,58,0,255,255,153,1,2,
51,255,255,58,0,255,255,149,1,2,
27,
51,255,255,58,0,255,255,153,1,2,
51,255,255,58,0,255,255,149,1,2,
57,26,0,0,
57,27,0,0,
57,28,0,0,0,
27,
51,255,255,58,0,255,255,97,1,2,
51,255,255,58,0,255,255,93,1,2,
27,
51,255,255,58,0,255,255,97,1,2,
51,255,255,58,0,255,255,93,1,2,
57,26,0,0,
57,27,0,0,
57,28,0,0,2,
@ -445,28 +445,28 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,59,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,112,1,1,
51,255,255,10,0,255,255,108,1,1,
27,
51,255,255,10,0,255,255,93,1,2,
27,
51,255,255,10,0,255,255,93,1,2,
27,
51,255,255,10,0,255,255,97,1,2,
27,
51,255,255,10,0,255,255,97,1,2,
27,
51,255,255,10,0,255,255,101,1,2,
57,26,0,0,
57,26,0,0,
27,
51,255,255,10,0,255,255,101,1,2,
51,255,255,10,0,255,255,97,1,2,
57,27,0,0,
57,27,0,0,
27,
51,255,255,10,0,255,255,101,1,2,
51,255,255,10,0,255,255,97,1,2,
57,28,0,0,
57,28,0,0,
56,60,0,
51,255,255,58,0,0,
1,
27,
51,255,255,58,0,255,255,93,1,3,
51,255,255,58,0,255,255,89,1,3,
13,
51,255,255,58,0,1,
1,
@ -479,9 +479,9 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,61,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,157,1,1,
51,255,255,10,0,255,255,153,1,1,
27,
51,255,255,10,0,255,255,93,1,3,
51,255,255,10,0,255,255,89,1,3,
25,
51,255,255,10,0,0,0,0,192,
57,29,0,0,
@ -490,11 +490,11 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,62,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,97,1,2,
51,255,255,10,0,255,255,93,1,2,
25,
51,255,255,10,0,0,0,0,0,
27,
51,255,255,10,0,255,255,93,1,3,
51,255,255,10,0,255,255,89,1,3,
57,59,0,0,
57,25,0,0,
25,
@ -504,7 +504,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
1,
1,
27,
51,255,255,10,0,255,255,161,1,1,
51,255,255,10,0,255,255,157,1,1,
57,60,0,0,2,
57,25,0,0,0,
1,
@ -516,7 +516,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
25,
51,255,255,10,0,0,0,128,64,2,
27,
51,255,255,10,0,255,255,153,1,2,
51,255,255,10,0,255,255,149,1,2,
57,29,0,0,
25,
51,255,255,10,0,0,0,128,63,
@ -528,7 +528,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,1,0,
55,65,0,
17,168,1,
17,164,1,
51,255,255,10,0,2,1,0,
0,0,2,
56,65,0,
@ -542,11 +542,11 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,35,0,0,
44,
27,
51,255,255,10,0,255,255,97,1,2,
51,255,255,10,0,255,255,93,1,2,
27,
51,255,255,10,0,255,255,107,1,1,
51,255,255,10,0,255,255,103,1,1,
27,
51,255,255,10,0,255,255,112,1,1,
51,255,255,10,0,255,255,108,1,1,
57,65,0,0,
25,
51,255,255,10,0,0,0,128,63,1,
@ -554,7 +554,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,1,0,
55,66,0,
17,168,1,
17,164,1,
51,255,255,10,0,2,1,0,
0,0,2,
56,66,0,
@ -568,12 +568,12 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
57,41,0,0,
44,
27,
51,255,255,10,0,255,255,107,1,1,
51,255,255,10,0,255,255,103,1,1,
1,
27,
51,255,255,10,0,255,255,117,1,1,
51,255,255,10,0,255,255,113,1,1,
27,
51,255,255,10,0,255,255,97,1,2,
51,255,255,10,0,255,255,93,1,2,
57,66,0,0,
25,
51,255,255,10,0,0,0,128,63,2,
@ -583,7 +583,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,1,0,
55,67,0,
17,171,1,
17,167,1,
51,255,255,58,0,2,1,0,
0,0,3,
56,67,0,
@ -591,7 +591,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
58,
32,0,
27,
51,255,255,182,1,255,255,187,1,1,
51,255,255,178,1,255,255,183,1,1,
50,
57,46,0,0,1,2,
2,
@ -630,13 +630,13 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
17,71,0,
51,255,255,58,0,2,
55,72,0,
17,176,0,
17,174,0,
51,255,255,10,0,2,
55,73,0,
17,193,1,
17,189,1,
51,255,255,10,0,2,
55,74,0,
17,209,1,
17,205,1,
51,255,255,10,0,2,7,0,
6,0,
5,0,
@ -672,7 +672,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
58,
32,0,
27,
51,255,255,182,1,255,255,187,1,1,
51,255,255,178,1,255,255,183,1,1,
50,
57,46,0,0,1,3,
2,
@ -728,12 +728,12 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
1,
57,44,0,1,15,
27,
51,255,255,10,0,255,255,223,1,1,
51,255,255,10,0,255,255,219,1,1,
27,
51,255,255,10,0,255,255,229,1,2,
51,255,255,10,0,255,255,225,1,2,
57,44,0,0,
12,
51,255,255,235,1,1,
51,255,255,231,1,1,
1,
57,73,0,0,1,
57,43,0,0,
@ -745,15 +745,15 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,74,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,223,1,1,
51,255,255,10,0,255,255,219,1,1,
1,
25,
51,255,255,10,0,0,0,0,63,0,
27,
51,255,255,10,0,255,255,229,1,2,
51,255,255,10,0,255,255,225,1,2,
57,44,0,0,
12,
51,255,255,235,1,1,
51,255,255,231,1,1,
1,
25,
51,255,255,10,0,0,0,160,64,1,
@ -771,34 +771,34 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
2,
52,1,10,0,
55,75,0,
17,239,1,
17,235,1,
51,255,255,10,0,2,
55,76,0,
17,241,1,
17,237,1,
51,255,255,58,0,2,
55,77,0,
17,244,1,
17,240,1,
51,255,255,58,0,2,
55,78,0,
17,247,1,
17,243,1,
51,255,255,58,0,2,
55,79,0,
17,250,1,
17,246,1,
51,255,255,58,0,2,
55,80,0,
17,254,1,
17,250,1,
51,255,255,58,0,2,
55,81,0,
17,2,2,
17,254,1,
51,255,255,58,0,2,
55,82,0,
17,7,2,
17,3,2,
51,255,255,10,0,2,
55,83,0,
17,9,2,
17,5,2,
51,255,255,10,0,2,
55,84,0,
17,11,2,
17,7,2,
51,255,255,10,0,2,10,0,
0,0,
1,0,
@ -819,49 +819,49 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,76,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,68,0,0,
57,69,0,0,
57,75,0,0,
56,77,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,69,0,0,
57,70,0,0,
57,75,0,0,
56,78,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,70,0,0,
57,71,0,0,
57,75,0,0,
56,79,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,76,0,0,
57,77,0,0,
57,75,0,0,
56,80,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,77,0,0,
57,78,0,0,
57,75,0,0,
56,81,0,
51,255,255,58,0,0,
27,
51,255,255,58,0,255,255,14,2,3,
51,255,255,58,0,255,255,10,2,3,
57,79,0,0,
57,80,0,0,
57,75,0,0,
56,82,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,14,2,3,
51,255,255,10,0,255,255,10,2,3,
25,
51,255,255,10,0,0,0,128,63,
57,72,0,0,
@ -877,7 +877,7 @@ static uint8_t SKSL_INCLUDE_sksl_graphite_vert[] = {10,0,16,2,
56,84,0,
51,255,255,10,0,0,
27,
51,255,255,10,0,255,255,14,2,3,
51,255,255,10,0,255,255,10,2,3,
57,82,0,0,
57,83,0,0,
57,75,0,0,

View File

@ -18,8 +18,8 @@ const float $LengthTermPow2 = (($Degree * $Degree) * (($Degree - 1) * ($Degree -
($Precision * $Precision);
// Returns the length squared of the largest forward difference from Wang's cubic formula.
float wangs_formula_max_fdiff_pow2(float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float wangs_formula_max_fdiff_p2(float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float2 d0 = matrix * (fma(float2(-2), p1, p2) + p0);
float2 d1 = matrix * (fma(float2(-2), p2, p3) + p1);
return max(dot(d0,d0), dot(d1,d1));
@ -27,17 +27,17 @@ float wangs_formula_max_fdiff_pow2(float2 p0, float2 p1, float2 p2, float2 p3,
float wangs_formula_cubic(float _precision_, float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float m = wangs_formula_max_fdiff_pow2(p0, p1, p2, p3, matrix);
float m = wangs_formula_max_fdiff_p2(p0, p1, p2, p3, matrix);
return max(ceil(sqrt($LengthTerm * _precision_ * sqrt(m))), 1.0);
}
float wangs_formula_cubic_log2(float _precision_, float2 p0, float2 p1, float2 p2, float2 p3,
float2x2 matrix) {
float m = wangs_formula_max_fdiff_pow2(p0, p1, p2, p3, matrix);
float m = wangs_formula_max_fdiff_p2(p0, p1, p2, p3, matrix);
return ceil(log2(max($LengthTermPow2 * _precision_ * _precision_ * m, 1.0)) * .25);
}
float wangs_formula_conic_pow2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float wangs_formula_conic_p2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
// Translate the bounding box center to the origin.
float2 C = (min(min(p0, p1), p2) + max(max(p0, p1), p2)) * 0.5;
p0 -= C;
@ -61,12 +61,12 @@ float wangs_formula_conic_pow2(float _precision_, float2 p0, float2 p1, float2 p
}
float wangs_formula_conic(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float n2 = wangs_formula_conic_pow2(_precision_, p0, p1, p2, w);
float n2 = wangs_formula_conic_p2(_precision_, p0, p1, p2, w);
return max(ceil(sqrt(n2)), 1.0);
}
float wangs_formula_conic_log2(float _precision_, float2 p0, float2 p1, float2 p2, float w) {
float n2 = wangs_formula_conic_pow2(_precision_, p0, p1, p2, w);
float n2 = wangs_formula_conic_p2(_precision_, p0, p1, p2, w);
return ceil(log2(max(n2, 1.0)) * .5);
}

View File

@ -342,7 +342,7 @@ DEF_TEST(wangs_formula_worst_case_cubic, r) {
}
// Make sure overflow saturates at infinity (not NaN).
constexpr static float inf = std::numeric_limits<float>::infinity();
REPORTER_ASSERT(r, wangs_formula::worst_case_cubic_pow4(kPrecision, inf, inf) == inf);
REPORTER_ASSERT(r, wangs_formula::worst_case_cubic_p4(kPrecision, inf, inf) == inf);
REPORTER_ASSERT(r, wangs_formula::worst_case_cubic(kPrecision, inf, inf) == inf);
}