blob: b42e36f6b2b1e74f09e081a69b8628ac43e7744e [file] [log] [blame]
Brian Salomona33b67c2018-05-17 10:42:14 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrQuad.h"
9
Michael Ludwig6bee7762018-10-19 09:50:36 -040010#include "GrTypesPriv.h"
11
Michael Ludwig1f7e4382018-10-19 09:36:57 -040012static bool aa_affects_rect(float ql, float qt, float qr, float qb) {
13 return !SkScalarIsInt(ql) || !SkScalarIsInt(qr) || !SkScalarIsInt(qt) || !SkScalarIsInt(qb);
14}
15
Michael Ludwige9c57d32019-02-13 13:39:39 -050016static void map_rect_translate_scale(const SkRect& rect, const SkMatrix& m,
17 Sk4f* xs, Sk4f* ys) {
18 SkMatrix::TypeMask tm = m.getType();
19 SkASSERT(tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
20
21 Sk4f r = Sk4f::Load(&rect);
22 if (tm > SkMatrix::kIdentity_Mask) {
23 const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
24 if (tm <= SkMatrix::kTranslate_Mask) {
25 r += t;
26 } else {
27 const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
28 r = r * s + t;
29 }
30 }
31 *xs = SkNx_shuffle<0, 0, 2, 2>(r);
32 *ys = SkNx_shuffle<1, 3, 1, 3>(r);
33}
34
35static void map_quad_general(const Sk4f& qx, const Sk4f& qy, const SkMatrix& m,
36 Sk4f* xs, Sk4f* ys, Sk4f* ws) {
37 static constexpr auto fma = SkNx_fma<4, float>;
38 *xs = fma(m.getScaleX(), qx, fma(m.getSkewX(), qy, m.getTranslateX()));
39 *ys = fma(m.getSkewY(), qx, fma(m.getScaleY(), qy, m.getTranslateY()));
40 if (m.hasPerspective()) {
41 Sk4f w = fma(m.getPerspX(), qx, fma(m.getPerspY(), qy, m.get(SkMatrix::kMPersp2)));
42 if (ws) {
43 // Output the calculated w coordinates
44 *ws = w;
45 } else {
46 // Apply perspective division immediately
47 Sk4f iw = w.invert();
48 *xs *= iw;
49 *ys *= iw;
50 }
51 } else if (ws) {
52 *ws = 1.f;
53 }
54}
55
56static void map_rect_general(const SkRect& rect, const SkMatrix& matrix,
57 Sk4f* xs, Sk4f* ys, Sk4f* ws) {
58 Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
59 Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
60 map_quad_general(rx, ry, matrix, xs, ys, ws);
61}
62
Michael Ludwig009b92e2019-02-15 16:03:53 -050063// Rearranges (top-left, top-right, bottom-right, bottom-left) ordered skQuadPts into xs and ys
64// ordered (top-left, bottom-left, top-right, bottom-right)
65static void rearrange_sk_to_gr_points(const SkPoint skQuadPts[4], Sk4f* xs, Sk4f* ys) {
66 *xs = Sk4f(skQuadPts[0].fX, skQuadPts[3].fX, skQuadPts[1].fX, skQuadPts[2].fX);
67 *ys = Sk4f(skQuadPts[0].fY, skQuadPts[3].fY, skQuadPts[1].fY, skQuadPts[2].fY);
68}
69
Michael Ludwig6bee7762018-10-19 09:50:36 -040070template <typename Q>
71void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
72 const Q& quad, GrQuadType knownType,
73 GrAAType* outAAType, GrQuadAAFlags* outEdgeFlags) {
74 // Most cases will keep the requested types unchanged
75 *outAAType = requestedAAType;
76 *outEdgeFlags = requestedEdgeFlags;
77
78 switch (requestedAAType) {
79 // When aa type is coverage, disable AA if the edge configuration doesn't actually need it
80 case GrAAType::kCoverage:
81 if (requestedEdgeFlags == GrQuadAAFlags::kNone) {
82 // Turn off anti-aliasing
83 *outAAType = GrAAType::kNone;
84 } else {
85 // For coverage AA, if the quad is a rect and it lines up with pixel boundaries
86 // then overall aa and per-edge aa can be completely disabled
Michael Ludwigc182b942018-11-16 10:27:51 -050087 if (knownType == GrQuadType::kRect && !quad.aaHasEffectOnRect()) {
Michael Ludwig6bee7762018-10-19 09:50:36 -040088 *outAAType = GrAAType::kNone;
89 *outEdgeFlags = GrQuadAAFlags::kNone;
90 }
91 }
92 break;
93 // For no or msaa anti aliasing, override the edge flags since edge flags only make sense
94 // when coverage aa is being used.
95 case GrAAType::kNone:
96 *outEdgeFlags = GrQuadAAFlags::kNone;
97 break;
98 case GrAAType::kMSAA:
99 *outEdgeFlags = GrQuadAAFlags::kAll;
100 break;
101 case GrAAType::kMixedSamples:
102 SK_ABORT("Should not use mixed sample AA with edge AA flags");
103 break;
104 }
105};
106
107// Instantiate GrResolve... for GrQuad and GrPerspQuad
108template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrQuad&, GrQuadType,
109 GrAAType*, GrQuadAAFlags*);
110template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrPerspQuad&, GrQuadType,
111 GrAAType*, GrQuadAAFlags*);
112
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400113GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix) {
114 if (matrix.rectStaysRect()) {
Michael Ludwigc182b942018-11-16 10:27:51 -0500115 return GrQuadType::kRect;
Michael Ludwigf995c052018-11-26 15:24:29 -0500116 } else if (matrix.preservesRightAngles()) {
117 return GrQuadType::kRectilinear;
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400118 } else if (matrix.hasPerspective()) {
Michael Ludwigc182b942018-11-16 10:27:51 -0500119 return GrQuadType::kPerspective;
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400120 } else {
Michael Ludwigc182b942018-11-16 10:27:51 -0500121 return GrQuadType::kStandard;
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400122 }
123}
124
Michael Ludwig97b94422019-04-09 10:42:39 -0400125GrQuadType GrQuadTypeForPoints(const SkPoint pts[4], const SkMatrix& matrix) {
126 if (matrix.hasPerspective()) {
127 return GrQuadType::kPerspective;
128 }
129 // If 'pts' was formed by SkRect::toQuad() and not transformed further, it is safe to use the
130 // quad type derived from 'matrix'. Otherwise don't waste any more time and assume kStandard
131 // (most general 2D quad).
Michael Ludwigd8d859a2019-04-18 13:43:58 -0400132 if ((pts[0].fX == pts[3].fX && pts[1].fX == pts[2].fX) &&
133 (pts[0].fY == pts[1].fY && pts[2].fY == pts[3].fY)) {
Michael Ludwig97b94422019-04-09 10:42:39 -0400134 return GrQuadTypeForTransformedRect(matrix);
135 } else {
136 return GrQuadType::kStandard;
137 }
138}
139
Michael Ludwige9c57d32019-02-13 13:39:39 -0500140GrQuad GrQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
141 Sk4f x, y;
Brian Salomona33b67c2018-05-17 10:42:14 -0400142 SkMatrix::TypeMask tm = m.getType();
143 if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500144 map_rect_translate_scale(rect, m, &x, &y);
Brian Salomona33b67c2018-05-17 10:42:14 -0400145 } else {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500146 map_rect_general(rect, m, &x, &y, nullptr);
Brian Salomona33b67c2018-05-17 10:42:14 -0400147 }
Michael Ludwige9c57d32019-02-13 13:39:39 -0500148 return GrQuad(x, y);
Brian Salomona33b67c2018-05-17 10:42:14 -0400149}
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400150
Michael Ludwig009b92e2019-02-15 16:03:53 -0500151GrQuad GrQuad::MakeFromSkQuad(const SkPoint pts[4], const SkMatrix& matrix) {
152 Sk4f xs, ys;
153 rearrange_sk_to_gr_points(pts, &xs, &ys);
154 if (matrix.isIdentity()) {
155 return GrQuad(xs, ys);
156 } else {
157 Sk4f mx, my;
158 map_quad_general(xs, ys, matrix, &mx, &my, nullptr);
159 return GrQuad(mx, my);
160 }
161}
162
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400163bool GrQuad::aaHasEffectOnRect() const {
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400164 return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
165}
166
Michael Ludwigc96fc372019-01-08 15:46:15 -0500167// Private constructor used by GrQuadList to quickly fill in a quad's values from the channel arrays
168GrPerspQuad::GrPerspQuad(const float* xs, const float* ys, const float* ws) {
169 memcpy(fX, xs, 4 * sizeof(float));
170 memcpy(fY, ys, 4 * sizeof(float));
171 memcpy(fW, ws, 4 * sizeof(float));
172}
173
Michael Ludwige9c57d32019-02-13 13:39:39 -0500174GrPerspQuad GrPerspQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
175 Sk4f x, y, w;
176 SkMatrix::TypeMask tm = m.getType();
177 if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
178 map_rect_translate_scale(rect, m, &x, &y);
179 w = 1.f;
180 } else {
181 map_rect_general(rect, m, &x, &y, &w);
182 }
183 return GrPerspQuad(x, y, w);
184}
185
Michael Ludwig009b92e2019-02-15 16:03:53 -0500186GrPerspQuad GrPerspQuad::MakeFromSkQuad(const SkPoint pts[4], const SkMatrix& matrix) {
187 Sk4f xs, ys;
188 rearrange_sk_to_gr_points(pts, &xs, &ys);
189 if (matrix.isIdentity()) {
190 return GrPerspQuad(xs, ys, 1.f);
191 } else {
192 Sk4f mx, my, mw;
193 map_quad_general(xs, ys, matrix, &mx, &my, &mw);
194 return GrPerspQuad(mx, my, mw);
195 }
196}
197
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400198bool GrPerspQuad::aaHasEffectOnRect() const {
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400199 // If rect, ws must all be 1s so no need to divide
200 return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
201}