26#define AI SK_ALWAYS_INLINE
39 return skvx::shuffle<2, 0, 3, 1>(v);
44 return skvx::shuffle<1, 3, 0, 2>(v);
49 return skvx::shuffle<3, 2, 1, 0>(v);
79 float lx[4],
float ly[4],
float lw[4]) {
85 float beta = 1.f - alpha;
86 lx[v0] = alpha * lx[v0] + beta * lx[
v2];
87 ly[v0] = alpha * ly[v0] + beta * ly[
v2];
88 lw[v0] = alpha * lw[v0] + beta * lw[
v2];
90 lx[v1] = alpha * lx[v1] + beta * lx[v3];
91 ly[v1] = alpha * ly[v1] + beta * ly[v3];
92 lw[v1] = alpha * lw[v1] + beta * lw[v3];
99 float x[4],
float y[4],
float lx[4],
float ly[4],
float lw[4]) {
110 float alpha = (
x[
v2] - clipDevRect.
fLeft) / (
x[
v2] -
x[v0]);
113 x[v0] = clipDevRect.
fLeft;
114 x[v1] = clipDevRect.
fLeft;
119 float alpha = (clipDevRect.
fRight -
x[
v2]) / (
x[v0] -
x[
v2]);
129 if (
y[v0] < clipDevRect.
fTop &&
y[
v2] >= clipDevRect.
fTop) {
132 float alpha = (
y[
v2] - clipDevRect.
fTop) / (
y[
v2] -
y[v0]);
135 y[v0] = clipDevRect.
fTop;
136 y[v1] = clipDevRect.
fTop;
157 float lx[4],
float ly[4],
float lw[4]) {
181 return clipEdgeFlags;
187 float lx[4],
float ly[4]) {
191 const SkScalar dx = lx ? (lx[2] - lx[0]) / (
x[2] -
x[0]) : 0.f;
192 const SkScalar dy = ly ? (ly[1] - ly[0]) / (
y[1] -
y[0]) : 0.f;
193 if (clipDevRect.
fLeft >
x[0]) {
195 lx[0] += (clipDevRect.
fLeft -
x[0]) *
dx;
202 if (clipDevRect.
fTop >
y[0]) {
204 ly[0] += (clipDevRect.
fTop -
y[0]) * dy;
207 y[0] = clipDevRect.
fTop;
208 y[2] = clipDevRect.
fTop;
211 if (clipDevRect.
fRight <
x[2]) {
213 lx[2] -= (
x[2] - clipDevRect.
fRight) *
dx;
222 ly[1] -= (
y[1] - clipDevRect.
fBottom) * dy;
230 return clipEdgeFlags;
254 static constexpr float kCoordLimit = 1e7f;
257 if (scaleX > kCoordLimit) {
258 scaleX = kCoordLimit / scaleX;
266 if (scaleY > kCoordLimit) {
267 scaleY = kCoordLimit / scaleY;
282 float dot00 = v0x * v0x + v0y * v0y;
283 float dot01 = v0x * v1x + v0y * v1y;
284 float dot11 = v1x * v1x + v1y * v1y;
292 float invDenom = dot00 * dot11 - dot01 * dot01;
305 float4 v2x = (scaleX * testX) - x0;
306 float4 v2y = (scaleY * testY) - y0;
308 float4 dot02 = v0x * v2x + v0y * v2y;
309 float4 dot12 = v1x * v2x + v1y * v2y;
312 *u = (dot11 * dot02 - dot01 * dot12) * invDenom;
313 *v = (dot00 * dot12 - dot01 * dot02) * invDenom;
320 return ((u >= 0.f) & (u <= 1.f)) & ((v >= 0.f) & (v <= 1.f)) & ((
w >= 0.f) & (
w <= 1.f));
325SkRect GrQuad::projectedBounds()
const {
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)) {
656 helper.
reset(quad,
nullptr);
683 fInvLengths = 1.f /
sqrt(fDX*fDX + fDY*fDY);
697 fInvSinTheta = 1.f /
sqrt(1.f - fCosTheta * fCosTheta);
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];
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);
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(
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);
static GrQuadAAFlags crop_rect(const SkRect &clipDevRect, float x[4], float y[4], float lx[4], float ly[4], float lw[4])
static void interpolate_local(float alpha, int v0, int v1, int v2, int v3, float lx[4], float ly[4], float lw[4])
static bool barycentric_coords(float x0, float y0, float x1, float y1, float x2, float y2, const float4 &testX, const float4 &testY, float4 *u, float4 *v, float4 *w)
static AI void correct_bad_edges(const mask4 &bad, float4 *e1, float4 *e2, float4 *e3)
static constexpr float kDistTolerance
static constexpr float kDist2Tolerance
static AI skvx::Vec< 4, T > next_ccw(const skvx::Vec< 4, T > &v)
static constexpr float kTolerance
static bool crop_rect_edge(const SkRect &clipDevRect, int v0, int v1, int v2, int v3, float x[4], float y[4], float lx[4], float ly[4], float lw[4])
static GrQuadAAFlags crop_simple_rect(const SkRect &clipDevRect, float x[4], float y[4], float lx[4], float ly[4])
static mask4 inside_triangle(const float4 &u, const float4 &v, const float4 &w)
static AI void correct_bad_coords(const mask4 &bad, float4 *c1, float4 *c2, float4 *c3)
static AI skvx::Vec< 4, T > next_cw(const skvx::Vec< 4, T > &v)
static AI float4 next_diag(const float4 &v)
static bool is_simple_rect(const GrQuad &quad)
static constexpr float kInvDistTolerance
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SK_ScalarNearlyZero
#define SK_ScalarInfinity
#define SK_ScalarNegativeInfinity
void getEdgeEquations(skvx::float4 *a, skvx::float4 *b, skvx::float4 *c)
void reset(const GrQuad &deviceQuad, const GrQuad *localQuad)
void outset(const skvx::float4 &edgeDistances, GrQuad *deviceOutset, GrQuad *localOutset)
skvx::float4 inset(const skvx::float4 &edgeDistances, GrQuad *deviceInset, GrQuad *localInset)
skvx::float4 getEdgeLengths()
skvx::Vec< 4, float > y4f() const
bool aaHasEffectOnRect(GrQuadAAFlags edgeFlags) const
bool hasPerspective() const
skvx::Vec< 4, float > x4f() const
void setQuadType(Type newType)
skvx::Vec< 4, float > w4f() const
static constexpr SkScalar kW0PlaneDistance
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
static float max(float r, float g, float b)
static float min(float r, float g, float b)
bool WillUseHairline(const GrQuad &quad, GrAAType aaType, GrQuadAAFlags edgeFlags)
bool CropToRect(const SkRect &cropRect, GrAA cropAA, DrawQuad *quad, bool computeLocal)
void ResolveAAType(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags, const GrQuad &quad, GrAAType *outAAType, GrQuadAAFlags *outEdgeFlags)
int ClipToW0(DrawQuad *quad, DrawQuad *extraVertices)
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
SIN Vec< N, float > abs(const Vec< N, float > &x)
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
SIT bool all(const Vec< 1, T > &x)
SIT bool any(const Vec< 1, T > &x)
SkScalar fBottom
larger y-axis bounds
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
SkScalar fTop
smaller y-axis bounds
SKVX_ALWAYS_INLINE void store(void *ptr) const