ccpr: Clip quadratic hulls more efficiently
To minimize area, we should clip by the tangent line at maximum
height. Not mid-tangent. This is also easier to find.
Bug: skia:
Change-Id: I5099b62537f72e51e29bbced7998c0e588e287d9
Reviewed-on: https://skia-review.googlesource.com/119740
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index 40339ba..6818027 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -113,10 +113,13 @@
// Called before generating geometry. Subclasses may set up internal member variables during
// this time that will be needed during onEmitVaryings (e.g. transformation matrices).
//
- // If the optional 'tighterHull' parameter is not null and gets filled out by the subclass,
- // the the Impl will generate geometry around those points rather than the input points.
+ // If the 'outHull4' parameter is provided, and there are not 4 input points, the subclass
+ // is required to fill it with the name of a 4-point hull around which the Impl can generate
+ // its geometry. If it is left unchanged, the Impl will use the regular input points.
virtual void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
- const char** tighterHull = nullptr) const {}
+ const char** outHull4 = nullptr) const {
+ SkASSERT(!outHull4);
+ }
void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
SkString* code, const char* position, const char* coverage,
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index 561a293..a1f180b 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -285,7 +285,7 @@
v->defineConstant("bloat", bloat);
const char* hullPts = "pts";
- fShader->emitSetupCode(v, "pts", "wind", &hullPts);
+ fShader->emitSetupCode(v, "pts", "wind", (4 == fNumSides) ? &hullPts : nullptr);
// Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0].
v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;",
diff --git a/src/gpu/ccpr/GrCCCubicShader.cpp b/src/gpu/ccpr/GrCCCubicShader.cpp
index 4c9485e..f8a8352 100644
--- a/src/gpu/ccpr/GrCCCubicShader.cpp
+++ b/src/gpu/ccpr/GrCCCubicShader.cpp
@@ -14,7 +14,7 @@
using Shader = GrCCCoverageProcessor::Shader;
void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* wind, const char** /*tighterHull*/) const {
+ const char* wind, const char** /*outHull4*/) const {
// Define a function that normalizes the homogeneous coordinates T=t/s in order to avoid
// exponent overflow.
SkString normalizeHomogCoordFn;
diff --git a/src/gpu/ccpr/GrCCCubicShader.h b/src/gpu/ccpr/GrCCCubicShader.h
index 2455880..d6c5e26 100644
--- a/src/gpu/ccpr/GrCCCubicShader.h
+++ b/src/gpu/ccpr/GrCCCubicShader.h
@@ -24,7 +24,7 @@
class GrCCCubicShader : public GrCCCoverageProcessor::Shader {
public:
void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
- const char** tighterHull) const override;
+ const char** outHull4) const override;
void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
const char* position, const char* coverage,
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp
index 2398282..00e16ce 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp
@@ -7,14 +7,11 @@
#include "GrCCQuadraticShader.h"
-#include "glsl/GrGLSLVertexGeoBuilder.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
-using Shader = GrCCCoverageProcessor::Shader;
-
void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* wind, const char** tighterHull) const {
+ const char* wind, const char** outHull4) const {
s->declareGlobal(fQCoordMatrix);
s->codeAppendf("%s = float2x2(1, 1, .5, 0) * inverse(float2x2(%s[2] - %s[0], %s[1] - %s[0]));",
fQCoordMatrix.c_str(), pts, pts, pts, pts);
@@ -27,21 +24,16 @@
s->codeAppendf("float2 edgept1 = %s[%s > 0 ? 0 : 2];", pts, wind);
Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str());
- if (tighterHull) {
- // Find the T value whose tangent is halfway between the tangents at the endpionts.
- s->codeAppendf("float2 tan0 = %s[1] - %s[0];", pts, pts);
- s->codeAppendf("float2 tan1 = %s[2] - %s[1];", pts, pts);
- s->codeAppend ("float2 midnorm = normalize(tan0) - normalize(tan1);");
- s->codeAppend ("float2 T = midnorm * float2x2(tan0 - tan1, tan0);");
- s->codeAppend ("float t = clamp(T.t / T.s, 0, 1);"); // T.s!=0; we cull flat curves on CPU.
-
- // Clip the bezier triangle by the tangent at our new t value. This is a simple application
- // for De Casteljau's algorithm.
- s->codeAppendf("float4x2 quadratic_hull = float4x2(%s[0], "
- "%s[0] + tan0 * t, "
- "%s[1] + tan1 * t, "
- "%s[2]);", pts, pts, pts, pts);
- *tighterHull = "quadratic_hull";
+ if (outHull4) {
+ // Clip the bezier triangle by the tangent line at maximum height. Quadratics have the nice
+ // property that maximum height always occurs at T=.5. This is a simple application for
+ // De Casteljau's algorithm.
+ s->codeAppendf("float2 quadratic_hull[4] = float2[4](%s[0], "
+ "(%s[0] + %s[1]) * .5, "
+ "(%s[1] + %s[2]) * .5, "
+ "%s[2]);",
+ pts, pts, pts, pts, pts, pts);
+ *outHull4 = "quadratic_hull";
}
}
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.h b/src/gpu/ccpr/GrCCQuadraticShader.h
index daf9eee..bf29b64 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.h
+++ b/src/gpu/ccpr/GrCCQuadraticShader.h
@@ -23,7 +23,7 @@
class GrCCQuadraticShader : public GrCCCoverageProcessor::Shader {
public:
void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
- const char** tighterHull) const override;
+ const char** outHull4) const override;
void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
const char* position, const char* coverage,