Reland "Change how GrTextureOp computes outset vertices."

This is a reland of 42e086cd2d

Original change's description:
> Change how GrTextureOp computes outset vertices.
> 
> Rather than intersecting outset edge equations we outset each vertex
> half a pixel along its two adjacent edges.
> 
> This approach will allow for water tight seams along shared edges
> when we allow a subset of the quad edges to be antialiased.
> 
> Bug: skia:
> Change-Id: I7f36ea658cc84dfcf364b138ec382bb709c278df
> Reviewed-on: https://skia-review.googlesource.com/156742
> Reviewed-by: Brian Osman <brianosman@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

Bug: skia:
Change-Id: I518ddf1d1bd6d7b8234db9ccba3c495eb42f3f1d
Reviewed-on: https://skia-review.googlesource.com/157562
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-09-26 20:25:23 -04:00 committed by Skia Commit-Bot
parent 5dd47e4f15
commit 1620b87565

View File

@ -275,37 +275,36 @@ static void compute_quad_edges_and_outset_vertices(Sk4f* x, Sk4f* y, Sk4f* a, Sk
auto nextCW = [](const Sk4f& v) { return SkNx_shuffle<2, 0, 3, 1>(v); }; auto nextCW = [](const Sk4f& v) { return SkNx_shuffle<2, 0, 3, 1>(v); };
auto nextCCW = [](const Sk4f& v) { return SkNx_shuffle<1, 3, 0, 2>(v); }; auto nextCCW = [](const Sk4f& v) { return SkNx_shuffle<1, 3, 0, 2>(v); };
// Compute edge equations for the quad.
auto xnext = nextCCW(*x); auto xnext = nextCCW(*x);
auto ynext = nextCCW(*y); auto ynext = nextCCW(*y);
*a = ynext - *y; // xdiff and ydiff will comprise the normalized vectors pointing along each quad edge.
*b = *x - xnext; auto xdiff = xnext - *x;
*c = fma(xnext, *y, -ynext * *x); auto ydiff = ynext - *y;
Sk4f invNormLengths = (*a * *a + *b * *b).rsqrt(); Sk4f invLengths = fma(xdiff, xdiff, ydiff * ydiff).rsqrt();
xdiff *= invLengths;
ydiff *= invLengths;
// Use above vectors to compute edge equations.
*c = fma(xnext, *y, -ynext * *x) * invLengths;
// Make sure the edge equations have their normals facing into the quad in device space. // Make sure the edge equations have their normals facing into the quad in device space.
auto test = fma(*a, nextCW(*x), fma(*b, nextCW(*y), *c)); auto test = fma(ydiff, nextCW(*x), fma(-xdiff, nextCW(*y), *c));
if ((test < Sk4f(0)).anyTrue()) { if ((test < Sk4f(0)).anyTrue()) {
invNormLengths = -invNormLengths; *a = -ydiff;
*b = xdiff;
*c = -*c;
} else {
*a = ydiff;
*b = -xdiff;
} }
*a *= invNormLengths; // Outset the edge equations so aa coverage evaluates to zero half a pixel away from the
*b *= invNormLengths; // original quad edge.
*c *= invNormLengths; *c += 0.5f;
// Here is the outset. This makes our edge equations compute coverage without requiring a // Outset the corners by half a pixel along each of the two adjacent vectors to ensure all
// half pixel offset and is also used to compute the bloated quad that will cover all // pixel centers are covered.
// pixels. *x += 0.5f * (-xdiff + nextCW(xdiff));
*c += Sk4f(0.5f); *y += 0.5f * (-ydiff + nextCW(ydiff));
// Reverse the process to compute the points of the bloated quad from the edge equations.
// This time the inputs don't have 1s as their third coord and we want to homogenize rather
// than normalize.
auto anext = nextCW(*a);
auto bnext = nextCW(*b);
auto cnext = nextCW(*c);
*x = fma(bnext, *c, -*b * cnext);
*y = fma(*a, cnext, -anext * *c);
auto ic = (fma(anext, *b, -bnext * *a)).invert();
*x *= ic;
*y *= ic;
} }
namespace { namespace {