Flutter Engine
The Flutter Engine
Namespaces | Macros | Typedefs | Functions | Variables
GrQuadUtils.cpp File Reference
#include "src/gpu/ganesh/geometry/GrQuadUtils.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/gpu/GrTypes.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/base/SkVx.h"
#include "src/core/SkPathPriv.h"
#include "src/gpu/ganesh/geometry/GrQuad.h"
#include <algorithm>
#include <cmath>

Go to the source code of this file.

Namespaces

namespace  GrQuadUtils
 

Macros

#define AI   SK_ALWAYS_INLINE
 

Typedefs

using float4 = skvx::float4
 
using mask4 = skvx::int4
 

Functions

template<typename T >
static AI skvx::Vec< 4, Tnext_cw (const skvx::Vec< 4, T > &v)
 
template<typename T >
static AI skvx::Vec< 4, Tnext_ccw (const skvx::Vec< 4, T > &v)
 
static AI float4 next_diag (const float4 &v)
 
static AI void correct_bad_edges (const mask4 &bad, float4 *e1, float4 *e2, float4 *e3)
 
static AI void correct_bad_coords (const mask4 &bad, float4 *c1, float4 *c2, float4 *c3)
 
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 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_rect (const SkRect &clipDevRect, 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 bool is_simple_rect (const GrQuad &quad)
 
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 mask4 inside_triangle (const float4 &u, const float4 &v, const float4 &w)
 
void GrQuadUtils::ResolveAAType (GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags, const GrQuad &quad, GrAAType *outAAType, GrQuadAAFlags *outEdgeFlags)
 
int GrQuadUtils::ClipToW0 (DrawQuad *quad, DrawQuad *extraVertices)
 
bool GrQuadUtils::CropToRect (const SkRect &cropRect, GrAA cropAA, DrawQuad *quad, bool computeLocal)
 
bool GrQuadUtils::WillUseHairline (const GrQuad &quad, GrAAType aaType, GrQuadAAFlags edgeFlags)
 

Variables

static constexpr float kTolerance = 1e-9f
 
static constexpr float kDistTolerance = 1e-2f
 
static constexpr float kDist2Tolerance = kDistTolerance * kDistTolerance
 
static constexpr float kInvDistTolerance = 1.f / kDistTolerance
 

Macro Definition Documentation

◆ AI

#define AI   SK_ALWAYS_INLINE

Definition at line 26 of file GrQuadUtils.cpp.

Typedef Documentation

◆ float4

Definition at line 23 of file GrQuadUtils.cpp.

◆ mask4

using mask4 = skvx::int4

Definition at line 24 of file GrQuadUtils.cpp.

Function Documentation

◆ barycentric_coords()

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

Definition at line 247 of file GrQuadUtils.cpp.

249 {
250 // The 32-bit calculations can have catastrophic cancellation if the device-space coordinates
251 // are really big, and this code needs to handle that because we evaluate barycentric coords
252 // pre-cropping to the render target bounds. This preserves some precision by shrinking the
253 // coordinate space if the bounds are large.
254 static constexpr float kCoordLimit = 1e7f; // Big but somewhat arbitrary, fixes crbug:10141204
255 float scaleX = std::max(std::max(x0, x1), x2) - std::min(std::min(x0, x1), x2);
256 float scaleY = std::max(std::max(y0, y1), y2) - std::min(std::min(y0, y1), y2);
257 if (scaleX > kCoordLimit) {
258 scaleX = kCoordLimit / scaleX;
259 x0 *= scaleX;
260 x1 *= scaleX;
261 x2 *= scaleX;
262 } else {
263 // Don't scale anything
264 scaleX = 1.f;
265 }
266 if (scaleY > kCoordLimit) {
267 scaleY = kCoordLimit / scaleY;
268 y0 *= scaleY;
269 y1 *= scaleY;
270 y2 *= scaleY;
271 } else {
272 scaleY = 1.f;
273 }
274
275 // Modeled after SkPathOpsQuad::pointInTriangle() but uses float instead of double, is
276 // vectorized and outputs normalized barycentric coordinates instead of inside/outside test
277 float v0x = x2 - x0;
278 float v0y = y2 - y0;
279 float v1x = x1 - x0;
280 float v1y = y1 - y0;
281
282 float dot00 = v0x * v0x + v0y * v0y;
283 float dot01 = v0x * v1x + v0y * v1y;
284 float dot11 = v1x * v1x + v1y * v1y;
285
286 // Not yet 1/d, first check d != 0 with a healthy tolerance (worst case is we end up not
287 // cropping something we could have, which is better than cropping something we shouldn't have).
288 // The tolerance is partly so large because these comparisons operate in device px^4 units,
289 // with plenty of subtractions thrown in. The SkPathOpsQuad code's use of doubles helped, and
290 // because it only needed to return "inside triangle", it could compare against [0, denom] and
291 // skip the normalization entirely.
292 float invDenom = dot00 * dot11 - dot01 * dot01;
293 static constexpr SkScalar kEmptyTriTolerance = SK_Scalar1 / (1 << 5);
294 if (SkScalarNearlyZero(invDenom, kEmptyTriTolerance)) {
295 // The triangle was degenerate/empty, which can cause the following UVW calculations to
296 // return (0,0,1) for every test point. This in turn makes the cropping code think that the
297 // empty triangle contains the crop rect and we turn the draw into a fullscreen clear, which
298 // is definitely the utter opposite of what we'd expect for an empty shape.
299 return false;
300 } else {
301 // Safe to divide
302 invDenom = sk_ieee_float_divide(1.f, invDenom);
303 }
304
305 float4 v2x = (scaleX * testX) - x0;
306 float4 v2y = (scaleY * testY) - y0;
307
308 float4 dot02 = v0x * v2x + v0y * v2y;
309 float4 dot12 = v1x * v2x + v1y * v2y;
310
311 // These are relative to the vertices, so there's no need to undo the scale factor
312 *u = (dot11 * dot02 - dot01 * dot12) * invDenom;
313 *v = (dot00 * dot12 - dot01 * dot02) * invDenom;
314 *w = 1.f - *u - *v;
315
316 return true;
317}
static constexpr float sk_ieee_float_divide(float numer, float denom)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
#define SK_Scalar1
Definition: SkScalar.h:18
float SkScalar
Definition: extension.cpp:12
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
SkScalar w
Definition: SkVx.h:83

◆ correct_bad_coords()

static AI void correct_bad_coords ( const mask4 bad,
float4 c1,
float4 c2,
float4 c3 
)
static

Definition at line 66 of file GrQuadUtils.cpp.

66 {
67 if (any(bad)) {
68 *c1 = if_then_else(bad, next_ccw(*c1), *c1);
69 *c2 = if_then_else(bad, next_ccw(*c2), *c2);
70 if (c3) {
71 *c3 = if_then_else(bad, next_ccw(*c3), *c3);
72 }
73 }
74}
static AI skvx::Vec< 4, T > next_ccw(const skvx::Vec< 4, T > &v)
Definition: GrQuadUtils.cpp:43
SI T if_then_else(C cond, T t, T e)
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530

◆ correct_bad_edges()

static AI void correct_bad_edges ( const mask4 bad,
float4 e1,
float4 e2,
float4 e3 
)
static

Definition at line 54 of file GrQuadUtils.cpp.

54 {
55 if (any(bad)) {
56 // Want opposite edges, L B T R -> R T B L but with flipped sign to preserve winding
57 *e1 = if_then_else(bad, -next_diag(*e1), *e1);
58 *e2 = if_then_else(bad, -next_diag(*e2), *e2);
59 if (e3) {
60 *e3 = if_then_else(bad, -next_diag(*e3), *e3);
61 }
62 }
63}
static AI float4 next_diag(const float4 &v)
Definition: GrQuadUtils.cpp:47
float e1

◆ crop_rect()

static GrQuadAAFlags crop_rect ( const SkRect clipDevRect,
float  x[4],
float  y[4],
float  lx[4],
float  ly[4],
float  lw[4] 
)
static

Definition at line 156 of file GrQuadUtils.cpp.

157 {
158 GrQuadAAFlags clipEdgeFlags = GrQuadAAFlags::kNone;
159
160 // The quad's left edge may not align with the SkRect notion of left due to 90 degree rotations
161 // or mirrors. So, this processes the logical edges of the quad and clamps it to the 4 sides of
162 // clipDevRect.
163
164 // Quad's left is v0 to v1 (op. v2 and v3)
165 if (crop_rect_edge(clipDevRect, 0, 1, 2, 3, x, y, lx, ly, lw)) {
166 clipEdgeFlags |= GrQuadAAFlags::kLeft;
167 }
168 // Quad's top edge is v0 to v2 (op. v1 and v3)
169 if (crop_rect_edge(clipDevRect, 0, 2, 1, 3, x, y, lx, ly, lw)) {
170 clipEdgeFlags |= GrQuadAAFlags::kTop;
171 }
172 // Quad's right edge is v2 to v3 (op. v0 and v1)
173 if (crop_rect_edge(clipDevRect, 2, 3, 0, 1, x, y, lx, ly, lw)) {
174 clipEdgeFlags |= GrQuadAAFlags::kRight;
175 }
176 // Quad's bottom edge is v1 to v3 (op. v0 and v2)
177 if (crop_rect_edge(clipDevRect, 1, 3, 0, 2, x, y, lx, ly, lw)) {
178 clipEdgeFlags |= GrQuadAAFlags::kBottom;
179 }
180
181 return clipEdgeFlags;
182}
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])
Definition: GrQuadUtils.cpp:98
GrQuadAAFlags
Definition: GrTypesPriv.h:247
double y
double x

◆ crop_rect_edge()

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

Definition at line 98 of file GrQuadUtils.cpp.

99 {
100 SkASSERT(v0 >= 0 && v0 < 4);
101 SkASSERT(v1 >= 0 && v1 < 4);
102 SkASSERT(v2 >= 0 && v2 < 4);
103 SkASSERT(v3 >= 0 && v3 < 4);
104
105 if (SkScalarNearlyEqual(x[v0], x[v1])) {
106 // A vertical edge
107 if (x[v0] < clipDevRect.fLeft && x[v2] >= clipDevRect.fLeft) {
108 // Overlapping with left edge of clipDevRect
109 if (lx) {
110 float alpha = (x[v2] - clipDevRect.fLeft) / (x[v2] - x[v0]);
111 interpolate_local(alpha, v0, v1, v2, v3, lx, ly, lw);
112 }
113 x[v0] = clipDevRect.fLeft;
114 x[v1] = clipDevRect.fLeft;
115 return true;
116 } else if (x[v0] > clipDevRect.fRight && x[v2] <= clipDevRect.fRight) {
117 // Overlapping with right edge of clipDevRect
118 if (lx) {
119 float alpha = (clipDevRect.fRight - x[v2]) / (x[v0] - x[v2]);
120 interpolate_local(alpha, v0, v1, v2, v3, lx, ly, lw);
121 }
122 x[v0] = clipDevRect.fRight;
123 x[v1] = clipDevRect.fRight;
124 return true;
125 }
126 } else {
127 // A horizontal edge
128 SkASSERT(SkScalarNearlyEqual(y[v0], y[v1]));
129 if (y[v0] < clipDevRect.fTop && y[v2] >= clipDevRect.fTop) {
130 // Overlapping with top edge of clipDevRect
131 if (lx) {
132 float alpha = (y[v2] - clipDevRect.fTop) / (y[v2] - y[v0]);
133 interpolate_local(alpha, v0, v1, v2, v3, lx, ly, lw);
134 }
135 y[v0] = clipDevRect.fTop;
136 y[v1] = clipDevRect.fTop;
137 return true;
138 } else if (y[v0] > clipDevRect.fBottom && y[v2] <= clipDevRect.fBottom) {
139 // Overlapping with bottom edge of clipDevRect
140 if (lx) {
141 float alpha = (clipDevRect.fBottom - y[v2]) / (y[v0] - y[v2]);
142 interpolate_local(alpha, v0, v1, v2, v3, lx, ly, lw);
143 }
144 y[v0] = clipDevRect.fBottom;
145 y[v1] = clipDevRect.fBottom;
146 return true;
147 }
148 }
149
150 // No overlap so don't crop it
151 return false;
152}
static void interpolate_local(float alpha, int v0, int v1, int v2, int v3, float lx[4], float ly[4], float lw[4])
Definition: GrQuadUtils.cpp:78
#define SkASSERT(cond)
Definition: SkAssert.h:116
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
Vec2Value v2
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15

◆ crop_simple_rect()

static GrQuadAAFlags crop_simple_rect ( const SkRect clipDevRect,
float  x[4],
float  y[4],
float  lx[4],
float  ly[4] 
)
static

Definition at line 186 of file GrQuadUtils.cpp.

187 {
188 GrQuadAAFlags clipEdgeFlags = GrQuadAAFlags::kNone;
189
190 // Update local coordinates proportionately to how much the device rect edge was clipped
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]) {
194 if (lx) {
195 lx[0] += (clipDevRect.fLeft - x[0]) * dx;
196 lx[1] = lx[0];
197 }
198 x[0] = clipDevRect.fLeft;
199 x[1] = clipDevRect.fLeft;
200 clipEdgeFlags |= GrQuadAAFlags::kLeft;
201 }
202 if (clipDevRect.fTop > y[0]) {
203 if (ly) {
204 ly[0] += (clipDevRect.fTop - y[0]) * dy;
205 ly[2] = ly[0];
206 }
207 y[0] = clipDevRect.fTop;
208 y[2] = clipDevRect.fTop;
209 clipEdgeFlags |= GrQuadAAFlags::kTop;
210 }
211 if (clipDevRect.fRight < x[2]) {
212 if (lx) {
213 lx[2] -= (x[2] - clipDevRect.fRight) * dx;
214 lx[3] = lx[2];
215 }
216 x[2] = clipDevRect.fRight;
217 x[3] = clipDevRect.fRight;
218 clipEdgeFlags |= GrQuadAAFlags::kRight;
219 }
220 if (clipDevRect.fBottom < y[1]) {
221 if (ly) {
222 ly[1] -= (y[1] - clipDevRect.fBottom) * dy;
223 ly[3] = ly[1];
224 }
225 y[1] = clipDevRect.fBottom;
226 y[3] = clipDevRect.fBottom;
227 clipEdgeFlags |= GrQuadAAFlags::kBottom;
228 }
229
230 return clipEdgeFlags;
231}
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208

◆ inside_triangle()

static mask4 inside_triangle ( const float4 u,
const float4 v,
const float4 w 
)
static

Definition at line 319 of file GrQuadUtils.cpp.

319 {
320 return ((u >= 0.f) & (u <= 1.f)) & ((v >= 0.f) & (v <= 1.f)) & ((w >= 0.f) & (w <= 1.f));
321}

◆ interpolate_local()

static void interpolate_local ( float  alpha,
int  v0,
int  v1,
int  v2,
int  v3,
float  lx[4],
float  ly[4],
float  lw[4] 
)
static

Definition at line 78 of file GrQuadUtils.cpp.

79 {
80 SkASSERT(v0 >= 0 && v0 < 4);
81 SkASSERT(v1 >= 0 && v1 < 4);
82 SkASSERT(v2 >= 0 && v2 < 4);
83 SkASSERT(v3 >= 0 && v3 < 4);
84
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];
89
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];
93}

◆ is_simple_rect()

static bool is_simple_rect ( const GrQuad quad)
static

Definition at line 234 of file GrQuadUtils.cpp.

234 {
235 if (quad.quadType() != GrQuad::Type::kAxisAligned) {
236 return false;
237 }
238 // v0 at the geometric top-left is unique, so we only need to compare x[0] < x[2] for left
239 // and y[0] < y[1] for top, but add a little padding to protect against numerical precision
240 // on R90 and R270 transforms tricking this check.
241 return ((quad.x(0) + SK_ScalarNearlyZero) < quad.x(2)) &&
242 ((quad.y(0) + SK_ScalarNearlyZero) < quad.y(1));
243}
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
float y(int i) const
Definition: GrQuad.h:109
Type quadType() const
Definition: GrQuad.h:118
float x(int i) const
Definition: GrQuad.h:108

◆ next_ccw()

template<typename T >
static AI skvx::Vec< 4, T > next_ccw ( const skvx::Vec< 4, T > &  v)
static

Definition at line 43 of file GrQuadUtils.cpp.

43 {
44 return skvx::shuffle<1, 3, 0, 2>(v);
45}

◆ next_cw()

template<typename T >
static AI skvx::Vec< 4, T > next_cw ( const skvx::Vec< 4, T > &  v)
static

Definition at line 38 of file GrQuadUtils.cpp.

38 {
39 return skvx::shuffle<2, 0, 3, 1>(v);
40}

◆ next_diag()

static AI float4 next_diag ( const float4 v)
static

Definition at line 47 of file GrQuadUtils.cpp.

47 {
48 // Same as next_ccw(next_ccw(v)), or next_cw(next_cw(v)), e.g. two rotations either direction.
49 return skvx::shuffle<3, 2, 1, 0>(v);
50}

Variable Documentation

◆ kDist2Tolerance

constexpr float kDist2Tolerance = kDistTolerance * kDistTolerance
staticconstexpr

Definition at line 32 of file GrQuadUtils.cpp.

◆ kDistTolerance

constexpr float kDistTolerance = 1e-2f
staticconstexpr

Definition at line 31 of file GrQuadUtils.cpp.

◆ kInvDistTolerance

constexpr float kInvDistTolerance = 1.f / kDistTolerance
staticconstexpr

Definition at line 33 of file GrQuadUtils.cpp.

◆ kTolerance

constexpr float kTolerance = 1e-9f
staticconstexpr

Definition at line 29 of file GrQuadUtils.cpp.