369 *outAAType = requestedAAType;
370 *outEdgeFlags = requestedEdgeFlags;
372 switch (requestedAAType) {
400 using Vertices = TessellationHelper::Vertices;
413 }
else if (!any(validW)) {
430 int clipCount = (validW[0] ? 0 : 1) + (validW[1] ? 0 : 1) +
431 (validW[2] ? 0 : 1) + (validW[3] ? 0 : 1);
432 SkASSERT(clipCount >= 1 && clipCount <= 3);
449 if (clipCount != 1) {
452 SkASSERT(clipCount == 2 || clipCount == 3);
478 &quad->
fLocal, localType);
484 mid.fX = 0.5f * (v.fX +
next_ccw(v.fX));
485 mid.fY = 0.5f * (v.fY +
next_ccw(v.fY));
486 mid.fW = 0.5f * (v.fW +
next_ccw(v.fW));
488 mid.fU = 0.5f * (v.fU +
next_ccw(v.fU));
489 mid.fV = 0.5f * (v.fV +
next_ccw(v.fV));
490 mid.fR = 0.5f * (v.fR +
next_ccw(v.fR));
495 v2.fUVRCount = v.fUVRCount;
538 &quad->
fLocal, localType);
542 &extraVertices->
fLocal, localType);
570 nullptr,
nullptr,
nullptr);
603 if (!
barycentric_coords(devX[0], devY[0], devX[1], devY[1], devX[2], devY[2], clipX, clipY,
605 !
barycentric_coords(devX[1], devY[1], devX[3], devY[3], devX[2], devY[2], clipX, clipY,
614 if (all(inTri1 | inTri2)) {
652 float d = std::min(std::abs(quad.
x(3) - quad.
x(0)), std::abs(quad.
y(3) - quad.
y(0)));
656 helper.
reset(quad,
nullptr);
683 fInvLengths = 1.f /
sqrt(fDX*fDX + fDY*fDY);
697 fInvSinTheta = 1.f /
sqrt(1.f - fCosTheta * fCosTheta);
703void TessellationHelper::EdgeEquations::reset(
const EdgeVectors& edgeVectors) {
705 float4 dy = edgeVectors.fDY;
709 float4 c =
dx*edgeVectors.fY2D - dy*edgeVectors.fX2D;
723float4 TessellationHelper::EdgeEquations::estimateCoverage(
const float4& x2d,
724 const float4& y2d)
const {
726 float4 d0 = fA[0]*x2d + (fB[0]*y2d + fC[0]);
727 float4 d1 = fA[1]*x2d + (fB[1]*y2d + fC[1]);
728 float4 d2 = fA[2]*x2d + (fB[2]*y2d + fC[2]);
729 float4 d3 = fA[3]*x2d + (fB[3]*y2d + fC[3]);
743bool TessellationHelper::EdgeEquations::isSubpixel(
const float4& x2d,
const float4& y2d)
const {
747 float4 d =
min(x2d * skvx::shuffle<1,2,1,2>(fA) + y2d * skvx::shuffle<1,2,1,2>(fB)
748 + skvx::shuffle<1,2,1,2>(fC),
749 x2d * skvx::shuffle<3,3,0,0>(fA) + y2d * skvx::shuffle<3,3,0,0>(fB)
750 + skvx::shuffle<3,3,0,0>(fC));
754int TessellationHelper::EdgeEquations::computeDegenerateQuad(
const float4& signedEdgeDistances,
756 mask4* aaMask)
const {
758 for (
int i = 0; i < 4; ++i) {
759 float4 d = (*x2d)*fA[i] + (*y2d)*fB[i] + fC[i];
766 *aaMask = signedEdgeDistances != 0.f;
769 float4 oc = fC + signedEdgeDistances;
782 float4 dists1 = px * skvx::shuffle<3, 3, 0, 0>(fA) +
783 py * skvx::shuffle<3, 3, 0, 0>(fB) +
784 skvx::shuffle<3, 3, 0, 0>(oc);
785 float4 dists2 = px * skvx::shuffle<1, 2, 1, 2>(fA) +
786 py * skvx::shuffle<1, 2, 1, 2>(fB) +
787 skvx::shuffle<1, 2, 1, 2>(oc);
797 mask4 d1And2 = d1v0 & d2v0;
798 mask4 d1Or2 = d1v0 | d2v0;
806 }
else if (
any(d1And2)) {
810 SkPoint center = {0.25f * ((*x2d)[0] + (*x2d)[1] + (*x2d)[2] + (*x2d)[3]),
811 0.25f * ((*y2d)[0] + (*y2d)[1] + (*y2d)[2] + (*y2d)[3])};
814 *aaMask =
any(*aaMask);
816 }
else if (
all(d1Or2)) {
821 *x2d = 0.5f * (skvx::shuffle<0, 1, 0, 1>(px) + skvx::shuffle<2, 3, 2, 3>(px));
822 *y2d = 0.5f * (skvx::shuffle<0, 1, 0, 1>(py) + skvx::shuffle<2, 3, 2, 3>(py));
826 *aaMask = *aaMask |
mask4({1, 0, 0, 1});
829 *x2d = 0.5f * (skvx::shuffle<0, 0, 2, 2>(px) + skvx::shuffle<1, 1, 3, 3>(px));
830 *y2d = 0.5f * (skvx::shuffle<0, 0, 2, 2>(py) + skvx::shuffle<1, 1, 3, 3>(py));
831 *aaMask = *aaMask |
mask4({0, 1, 1, 0});
845 V2f eDenom = skvx::shuffle<0, 1>(fA) * skvx::shuffle<3, 2>(fB) -
846 skvx::shuffle<0, 1>(fB) * skvx::shuffle<3, 2>(fA);
847 V2f ex = (skvx::shuffle<0, 1>(fB) * skvx::shuffle<3, 2>(oc) -
848 skvx::shuffle<0, 1>(oc) * skvx::shuffle<3, 2>(fB)) / eDenom;
849 V2f ey = (skvx::shuffle<0, 1>(oc) * skvx::shuffle<3, 2>(fA) -
850 skvx::shuffle<0, 1>(fA) * skvx::shuffle<3, 2>(oc)) / eDenom;
852 float4 avgX = 0.5f * (skvx::shuffle<0, 1, 0, 2>(px) + skvx::shuffle<2, 3, 1, 3>(px));
853 float4 avgY = 0.5f * (skvx::shuffle<0, 1, 0, 2>(py) + skvx::shuffle<2, 3, 1, 3>(py));
854 for (
int i = 0; i < 4; ++i) {
860 }
else if (d1v0[i]) {
866 }
else if (d2v0[i]) {
867 px[i] = avgX[i / 2 + 2];
868 py[i] = avgY[i / 2 + 2];
888void TessellationHelper::OutsetRequest::reset(
const EdgeVectors& edgeVectors,
GrQuad::Type quadType,
890 fEdgeDistances = edgeDistances;
899 fOutsetDegenerate =
false;
900 float widthChange = edgeDistances[0] + edgeDistances[3];
901 float heightChange = edgeDistances[1] + edgeDistances[2];
904 (widthChange > 0.f && edgeVectors.fInvLengths[1] > 1.f / widthChange) ||
905 (heightChange > 0.f && edgeVectors.fInvLengths[0] > 1.f / heightChange);
909 fOutsetDegenerate =
true;
910 fInsetDegenerate =
true;
914 if (
any(
abs(edgeVectors.fCosTheta) >= 0.9f)) {
915 fOutsetDegenerate =
true;
916 fInsetDegenerate =
true;
925 float4 halfTanTheta = -edgeVectors.fCosTheta * edgeVectors.fInvSinTheta;
926 float4 edgeAdjust = edgeDistances * (halfTanTheta +
next_ccw(halfTanTheta)) +
928 next_cw(edgeDistances) * edgeVectors.fInvSinTheta;
932 float4 threshold = 0.1f - (1.f / edgeVectors.fInvLengths);
933 fOutsetDegenerate =
any(edgeAdjust < threshold);
934 fInsetDegenerate =
any(edgeAdjust > -threshold);
941void TessellationHelper::Vertices::reset(
const GrQuad& deviceQuad,
const GrQuad* localQuad) {
943 fX = deviceQuad.
x4f();
944 fY = deviceQuad.
y4f();
945 fW = deviceQuad.
w4f();
948 fU = localQuad->
x4f();
949 fV = localQuad->
y4f();
950 fR = localQuad->
w4f();
957void TessellationHelper::Vertices::asGrQuads(
GrQuad* deviceOut,
GrQuad::Type deviceType,
960 SkASSERT(fUVRCount == 0 || localOut);
962 fX.store(deviceOut->
xs());
963 fY.store(deviceOut->
ys());
965 fW.store(deviceOut->
ws());
970 fU.store(localOut->
xs());
971 fV.store(localOut->
ys());
972 if (fUVRCount == 3) {
973 fR.store(localOut->
ws());
979void TessellationHelper::Vertices::moveAlong(
const EdgeVectors& edgeVectors,
980 const float4& signedEdgeDistances) {
985 any(edgeVectors.fCosTheta != edgeVectors.fCosTheta));
992 float4 signedOutsets = -edgeVectors.fInvSinTheta *
next_cw(signedEdgeDistances);
993 float4 signedOutsetsCW = edgeVectors.fInvSinTheta * signedEdgeDistances;
996 fX += signedOutsetsCW *
next_cw(edgeVectors.fDX) + signedOutsets * edgeVectors.fDX;
997 fY += signedOutsetsCW *
next_cw(edgeVectors.fDY) + signedOutsets * edgeVectors.fDY;
1000 signedOutsets *= edgeVectors.fInvLengths;
1001 signedOutsetsCW *=
next_cw(edgeVectors.fInvLengths);
1004 fU += signedOutsetsCW *
next_cw(du) + signedOutsets * du;
1005 fV += signedOutsetsCW *
next_cw(dv) + signedOutsets * dv;
1006 if (fUVRCount == 3) {
1008 fR += signedOutsetsCW *
next_cw(
dr) + signedOutsets *
dr;
1013void TessellationHelper::Vertices::moveTo(
const float4& x2d,
const float4& y2d,
const mask4& mask) {
1015 float4 e1x = skvx::shuffle<2, 3, 2, 3>(fX) - skvx::shuffle<0, 1, 0, 1>(fX);
1016 float4 e1y = skvx::shuffle<2, 3, 2, 3>(fY) - skvx::shuffle<0, 1, 0, 1>(fY);
1017 float4 e1w = skvx::shuffle<2, 3, 2, 3>(fW) - skvx::shuffle<0, 1, 0, 1>(fW);
1022 float4 e2x = skvx::shuffle<1, 1, 3, 3>(fX) - skvx::shuffle<0, 0, 2, 2>(fX);
1023 float4 e2y = skvx::shuffle<1, 1, 3, 3>(fY) - skvx::shuffle<0, 0, 2, 2>(fY);
1024 float4 e2w = skvx::shuffle<1, 1, 3, 3>(fW) - skvx::shuffle<0, 0, 2, 2>(fW);
1033 float4 c1x = e1w * x2d - e1x;
1034 float4 c1y = e1w * y2d - e1y;
1035 float4 c2x = e2w * x2d - e2x;
1036 float4 c2y = e2w * y2d - e2y;
1037 float4 c3x = fW * x2d - fX;
1038 float4 c3y = fW * y2d - fY;
1044 denom = c1x * c2y - c2x * c1y;
1045 a = (c2x * c3y - c3x * c2y) / denom;
1046 b = (c3x * c1y - c1x * c3y) / denom;
1049 mask4 aMask = skvx::shuffle<0, 0, 3, 3>(mask);
1050 mask4 bMask = skvx::shuffle<2, 1, 2, 1>(mask);
1061 c1x * c2y - c2x * c1y,
1069 c2x * c3y - c3x * c2y,
1074 c3x * c1y - c1x * c3y,
1079 fX +=
a * e1x +
b * e2x;
1080 fY +=
a * e1y +
b * e2y;
1081 fW +=
a * e1w +
b * e2w;
1088 if (
any(fW < 0.f)) {
1097 if (fUVRCount > 0) {
1099 float4 e1u = skvx::shuffle<2, 3, 2, 3>(fU) - skvx::shuffle<0, 1, 0, 1>(fU);
1100 float4 e1v = skvx::shuffle<2, 3, 2, 3>(fV) - skvx::shuffle<0, 1, 0, 1>(fV);
1101 float4 e1r = skvx::shuffle<2, 3, 2, 3>(fR) - skvx::shuffle<0, 1, 0, 1>(fR);
1104 float4 e2u = skvx::shuffle<1, 1, 3, 3>(fU) - skvx::shuffle<0, 0, 2, 2>(fU);
1105 float4 e2v = skvx::shuffle<1, 1, 3, 3>(fV) - skvx::shuffle<0, 0, 2, 2>(fV);
1106 float4 e2r = skvx::shuffle<1, 1, 3, 3>(fR) - skvx::shuffle<0, 0, 2, 2>(fR);
1109 fU +=
a * e1u +
b * e2u;
1110 fV +=
a * e1v +
b * e2v;
1111 if (fUVRCount == 3) {
1112 fR +=
a * e1r +
b * e2r;
1124 fDeviceType = deviceQuad.
quadType();
1128 fOutsetRequestValid =
false;
1129 fEdgeEquationsValid =
false;
1132 fOriginal.reset(deviceQuad, localQuad);
1133 fEdgeVectors.reset(fOriginal.fX, fOriginal.fY, fOriginal.fW, fDeviceType);
1135 fVerticesValid =
true;
1142 Vertices
inset = fOriginal;
1143 const OutsetRequest& request = this->getOutsetRequest(edgeDistances);
1145 if (request.fInsetDegenerate) {
1146 vertexCount = this->adjustDegenerateVertices(-request.fEdgeDistances, &
inset);
1148 this->adjustVertices(-request.fEdgeDistances, &
inset);
1152 inset.asGrQuads(deviceInset, fDeviceType, localInset, fLocalType);
1153 if (vertexCount < 3) {
1167 Vertices
outset = fOriginal;
1168 const OutsetRequest& request = this->getOutsetRequest(edgeDistances);
1169 if (request.fOutsetDegenerate) {
1170 this->adjustDegenerateVertices(request.fEdgeDistances, &
outset);
1172 this->adjustVertices(request.fEdgeDistances, &
outset);
1175 outset.asGrQuads(deviceOutset, fDeviceType, localOutset, fLocalType);
1191 return 1.f / fEdgeVectors.fInvLengths;
1194const TessellationHelper::OutsetRequest& TessellationHelper::getOutsetRequest(
1198 SkASSERT(all(edgeDistances >= 0.f));
1201 if (!fOutsetRequestValid || any(edgeDistances != fOutsetRequest.fEdgeDistances)) {
1202 fOutsetRequest.reset(fEdgeVectors, fDeviceType, edgeDistances);
1203 fOutsetRequestValid =
true;
1205 return fOutsetRequest;
1213 return any(fEdgeVectors.fInvLengths > 1.f);
1216 return this->
getEdgeEquations().isSubpixel(fEdgeVectors.fX2D, fEdgeVectors.fY2D);
1220const TessellationHelper::EdgeEquations& TessellationHelper::getEdgeEquations() {
1221 if (!fEdgeEquationsValid) {
1222 fEdgeEquations.reset(fEdgeVectors);
1223 fEdgeEquationsValid =
true;
1225 return fEdgeEquations;
1229 Vertices* vertices) {
1231 SkASSERT(vertices->fUVRCount == 0 || vertices->fUVRCount == 2 || vertices->fUVRCount == 3);
1235 vertices->moveAlong(fEdgeVectors, signedEdgeDistances);
1239 Vertices projected = { fEdgeVectors.fX2D, fEdgeVectors.fY2D, 1.f, 0.f, 0.f, 0.f, 0 };
1240 projected.moveAlong(fEdgeVectors, signedEdgeDistances);
1241 vertices->moveTo(projected.fX, projected.fY, signedEdgeDistances != 0.f);
1245int TessellationHelper::adjustDegenerateVertices(
const skvx::Vec<4, float>& signedEdgeDistances,
1246 Vertices* vertices) {
1248 SkASSERT(vertices->fUVRCount == 0 || vertices->fUVRCount == 2 || vertices->fUVRCount == 3);
1254 float4 halfLengths = -0.5f /
next_cw(fEdgeVectors.fInvLengths);
1255 mask4 crossedEdges = halfLengths > signedEdgeDistances;
1257 vertices->moveAlong(fEdgeVectors, safeInsets);
1260 return all(crossedEdges) ? 1 : 2;
1264 float4 x2d = fEdgeVectors.fX2D;
1265 float4 y2d = fEdgeVectors.fY2D;
1268 int vertexCount = this->
getEdgeEquations().computeDegenerateQuad(signedEdgeDistances,
1269 &x2d, &y2d, &aaMask);
1270 vertices->moveTo(x2d, y2d, aaMask);