ccpr: Fix very small edges
Fixes a bug in the vertex shader backend where a pixel could be hit
twice on very small, axis-aligned edges.
Improves the coverage calculations to be more accurate when dealing with
very small edges.
Bug: skia:
Change-Id: I4bac191695d7b7d73b6eef9df0fca3539503a965
Reviewed-on: https://skia-review.googlesource.com/111323
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index fc4409d..8c85a75 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -44,6 +44,41 @@
s->codeAppendf("%s = float3(-n, dot(n, %s) - .5);", outputDistanceEquation, leftPt);
}
+void GrCCCoverageProcessor::Shader::CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGeoBuilder* s,
+ const char* leftPt,
+ const char* rightPt,
+ const char* rasterVertexDir,
+ const char* outputCoverage) {
+ // Here we find an edge's coverage at one corner of a conservative raster bloat box whose center
+ // falls on the edge in question. (A bloat box is axis-aligned and the size of one pixel.) We
+ // always set up coverage so it is -1 at the outermost corner, 0 at the innermost, and -.5 at
+ // the center. Interpolated, these coverage values convert jagged conservative raster edges into
+ // smooth antialiased edges.
+ //
+ // d1 == (P + sign(n) * bloat) dot n (Distance at the bloat box vertex whose
+ // == P dot n + (abs(n.x) + abs(n.y)) * bloatSize coverage=-1, where the bloat box is
+ // centered on P.)
+ //
+ // d0 == (P - sign(n) * bloat) dot n (Distance at the bloat box vertex whose
+ // == P dot n - (abs(n.x) + abs(n.y)) * bloatSize coverage=0, where the bloat box is
+ // centered on P.)
+ //
+ // d == (P + rasterVertexDir * bloatSize) dot n (Distance at the bloat box vertex whose
+ // == P dot n + (rasterVertexDir dot n) * bloatSize coverage we wish to calculate.)
+ //
+ // coverage == -(d - d0) / (d1 - d0) (coverage=-1 at d=d1; coverage=0 at d=d0)
+ //
+ // == (rasterVertexDir dot n) / (abs(n.x) + abs(n.y)) * -.5 - .5
+ //
+ s->codeAppendf("float2 n = float2(%s.y - %s.y, %s.x - %s.x);",
+ rightPt, leftPt, leftPt, rightPt);
+ s->codeAppend ("float nwidth = abs(n.x) + abs(n.y);");
+ s->codeAppendf("float t = dot(%s, n);", rasterVertexDir);
+ // The below conditional guarantees we get exactly 1 on the divide when nwidth=t (in case the
+ // GPU divides by multiplying by the reciprocal?) It also guards against NaN when nwidth=0.
+ s->codeAppendf("%s = (abs(t) != nwidth ? t / nwidth : sign(t)) * -.5 - .5;", outputCoverage);
+}
+
int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLFPFragmentBuilder* f,
const char* samplesName) {
// Standard DX11 sample locations.