ccpr: Replace curve corner MSAA with analytic attenuation
Begins using the new triangle corner algorithm on curves as well.
Updates the vertex backend to render curves in a single pass.
Simplifies the cubic and quadratic shaders. Removes all code related to
sample locations.
Bug: skia:
Change-Id: I96c6c401be765e96a8fe087deb7f84760e68dcf0
Reviewed-on: https://skia-review.googlesource.com/115746
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp
index 5bee85e..287e63e 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp
@@ -14,8 +14,7 @@
using Shader = GrCCCoverageProcessor::Shader;
void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* repetitionID, const char* wind,
- GeometryVars* vars) const {
+ const char* wind, const char** tighterHull) 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);
@@ -28,113 +27,60 @@
s->codeAppendf("float2 edgept1 = %s[%s > 0 ? 0 : 2];", pts, wind);
Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str());
- this->onEmitSetupCode(s, pts, repetitionID, vars);
+ 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";
+ }
}
void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
GrGLSLVarying::Scope scope, SkString* code,
const char* position, const char* coverage,
- const char* attenuatedCoverage, const char* wind) {
- SkASSERT(!coverage);
- SkASSERT(!attenuatedCoverage);
+ const char* attenuatedCoverage) {
+ fCoord.reset(kFloat4_GrSLType, scope);
+ varyingHandler->addVarying("coord", &fCoord);
+ code->appendf("%s.xy = %s * (%s - %s);", // Quadratic coords.
+ OutName(fCoord), fQCoordMatrix.c_str(), position, fQCoord0.c_str());
+ code->appendf("%s.zw = 2*bloat * float2(2 * %s.x, -1) * %s;", // Gradient.
+ OutName(fCoord), OutName(fCoord), fQCoordMatrix.c_str());
- fXYDW.reset(kFloat4_GrSLType, scope);
- varyingHandler->addVarying("xydw", &fXYDW);
- code->appendf("%s.xy = %s * (%s - %s);",
- OutName(fXYDW), fQCoordMatrix.c_str(), position, fQCoord0.c_str());
- code->appendf("%s.z = dot(%s.xy, %s) + %s.z;",
- OutName(fXYDW), fEdgeDistanceEquation.c_str(), position,
- fEdgeDistanceEquation.c_str());
- code->appendf("%s.w = %s;", OutName(fXYDW), wind);
-
- this->onEmitVaryings(varyingHandler, scope, code);
+ // Coverages need full precision since distance to the opposite edge can be large.
+ fCoverages.reset(attenuatedCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope);
+ varyingHandler->addVarying("coverages", &fCoverages);
+ code->appendf("%s.x = dot(%s, float3(%s, 1));", // Distance to flat edge opposite the curve.
+ OutName(fCoverages), fEdgeDistanceEquation.c_str(), position);
+ code->appendf("%s.y = %s;", OutName(fCoverages), coverage); // Wind.
+ if (attenuatedCoverage) {
+ code->appendf("%s.zw = %s;", // Attenuated corner coverage.
+ OutName(fCoverages), attenuatedCoverage);
+ }
}
void GrCCQuadraticShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f,
const char* outputCoverage) const {
- this->emitCoverage(f, outputCoverage);
- f->codeAppendf("%s *= %s.w;", outputCoverage, fXYDW.fsIn()); // Sign by wind.
-}
-
-void GrCCQuadraticHullShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* /*repetitionID*/,
- GeometryVars* vars) const {
- // 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);
- vars->fHullVars.fAlternatePoints = "quadratic_hull";
-}
-
-void GrCCQuadraticHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code) {
- fGrad.reset(kFloat2_GrSLType, scope);
- varyingHandler->addVarying("grad", &fGrad);
- code->appendf("%s = 2*bloat * float2(2 * %s.x, -1) * %s;",
- OutName(fGrad), OutName(fXYDW), fQCoordMatrix.c_str());
-}
-
-void GrCCQuadraticHullShader::emitCoverage(GrGLSLFPFragmentBuilder* f,
- const char* outputCoverage) const {
- f->codeAppendf("float d = (%s.x * %s.x - %s.y) * inversesqrt(dot(%s, %s));",
- fXYDW.fsIn(), fXYDW.fsIn(), fXYDW.fsIn(), fGrad.fsIn(), fGrad.fsIn());
- f->codeAppendf("%s = clamp(0.5 - d, 0, 1);", outputCoverage);
- f->codeAppendf("%s += min(%s.z, 0);", outputCoverage, fXYDW.fsIn()); // Flat closing edge.
-}
-
-void GrCCQuadraticCornerShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* repetitionID,
- GeometryVars* vars) const {
- s->codeAppendf("float2 corner = %s[%s * 2];", pts, repetitionID);
- vars->fCornerVars.fPoint = "corner";
-}
-
-void GrCCQuadraticCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code) {
- using Interpolation = GrGLSLVaryingHandler::Interpolation;
-
- fdXYDdx.reset(kFloat3_GrSLType, scope);
- varyingHandler->addVarying("dXYDdx", &fdXYDdx, Interpolation::kCanBeFlat);
- code->appendf("%s = 2*bloat * float3(%s[0].x, %s[0].y, %s.x);",
- OutName(fdXYDdx), fQCoordMatrix.c_str(), fQCoordMatrix.c_str(),
- fEdgeDistanceEquation.c_str());
-
- fdXYDdy.reset(kFloat3_GrSLType, scope);
- varyingHandler->addVarying("dXYDdy", &fdXYDdy, Interpolation::kCanBeFlat);
- code->appendf("%s = 2*bloat * float3(%s[1].x, %s[1].y, %s.y);",
- OutName(fdXYDdy), fQCoordMatrix.c_str(), fQCoordMatrix.c_str(),
- fEdgeDistanceEquation.c_str());
-}
-
-void GrCCQuadraticCornerShader::emitCoverage(GrGLSLFPFragmentBuilder* f,
- const char* outputCoverage) const {
- f->codeAppendf("float x = %s.x, y = %s.y, d = %s.z;",
- fXYDW.fsIn(), fXYDW.fsIn(), fXYDW.fsIn());
- f->codeAppendf("float2x3 grad_xyd = float2x3(%s, %s);", fdXYDdx.fsIn(), fdXYDdy.fsIn());
-
- // Erase what the previous hull shader wrote. We don't worry about the two corners falling on
- // the same pixel because those cases should have been weeded out by this point.
+ f->codeAppendf("float x = %s.x, y = %s.y;", fCoord.fsIn(), fCoord.fsIn());
f->codeAppend ("float f = x*x - y;");
- f->codeAppend ("float2 grad_f = float2(2*x, -1) * float2x2(grad_xyd);");
- f->codeAppendf("%s = -(0.5 - f * inversesqrt(dot(grad_f, grad_f)));", outputCoverage);
- f->codeAppendf("%s -= d;", outputCoverage);
+ f->codeAppendf("float2 grad = %s.zw;", fCoord.fsIn());
+ f->codeAppendf("%s = clamp(0.5 - f * inversesqrt(dot(grad, grad)), 0, 1);", outputCoverage);
- // Use software msaa to approximate coverage at the corner pixels.
- int sampleCount = Shader::DefineSoftSampleLocations(f, "samples");
- f->codeAppendf("float3 xyd_center = float3(%s.xy, %s.z + 0.5);", fXYDW.fsIn(), fXYDW.fsIn());
- f->codeAppendf("for (int i = 0; i < %i; ++i) {", sampleCount);
- f->codeAppend ( "float3 xyd = grad_xyd * samples[i] + xyd_center;");
- f->codeAppend ( "half f = xyd.y - xyd.x * xyd.x;"); // f > 0 -> inside curve.
- f->codeAppendf( "%s += all(greaterThan(float2(f,xyd.z), float2(0))) ? %f : 0;",
- outputCoverage, 1.0 / sampleCount);
- f->codeAppendf("}");
+ f->codeAppendf("half d = min(%s.x, 0);", fCoverages.fsIn()); // Flat edge opposite the curve.
+ f->codeAppendf("half wind = %s.y;", fCoverages.fsIn());
+ f->codeAppendf("%s = (%s + d) * wind;", outputCoverage, outputCoverage);
+
+ if (kFloat4_GrSLType == fCoverages.type()) {
+ f->codeAppendf("%s = %s.z * %s.w + %s;", // Attenuated corner coverage.
+ outputCoverage, fCoverages.fsIn(), fCoverages.fsIn(), outputCoverage);
+ }
}