Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | Static Public Member Functions | List of all members
skgpu::graphite::Transform Class Reference

#include <Transform_graphite.h>

Public Types

enum class  Type : unsigned {
  kIdentity , kSimpleRectStaysRect , kRectStaysRect , kAffine ,
  kPerspective , kInvalid
}
 

Public Member Functions

 Transform (const SkM44 &m)
 
 Transform (const Transform &t)=default
 
Transformoperator= (const Transform &t)=default
 
 operator const SkM44 & () const
 
 operator SkMatrix () const
 
bool operator!= (const Transform &t) const
 
bool operator== (const Transform &t) const
 
const SkM44matrix () const
 
const SkM44inverse () const
 
Type type () const
 
bool valid () const
 
std::pair< float, float > scaleFactors (const SkV2 &p) const
 
float maxScaleFactor () const
 
float localAARadius (const Rect &bounds) const
 
Rect mapRect (const Rect &rect) const
 
Rect inverseMapRect (const Rect &rect) const
 
void mapPoints (const Rect &localRect, SkV4 deviceOut[4]) const
 
void mapPoints (const SkV2 *localIn, SkV4 *deviceOut, int count) const
 
void mapPoints (const SkV4 *localIn, SkV4 *deviceOut, int count) const
 
void inverseMapPoints (const SkV4 *deviceIn, SkV4 *localOut, int count) const
 
Transform preTranslate (float x, float y) const
 
Transform postTranslate (float x, float y) const
 
Transform concat (const Transform &t) const
 
Transform concat (const SkM44 &t) const
 
Transform concatInverse (const Transform &t) const
 
Transform concatInverse (const SkM44 &t) const
 

Static Public Member Functions

static constexpr Transform Identity ()
 
static constexpr Transform Invalid ()
 
static Transform Translate (float x, float y)
 
static Transform Inverse (const Transform &t)
 

Detailed Description

Definition at line 19 of file Transform_graphite.h.

Member Enumeration Documentation

◆ Type

enum class skgpu::graphite::Transform::Type : unsigned
strong
Enumerator
kIdentity 
kSimpleRectStaysRect 
kRectStaysRect 
kAffine 
kPerspective 
kInvalid 

Definition at line 23 of file Transform_graphite.h.

23 : unsigned {
24 // Applying the matrix to a vector or point is a no-op, so could be skipped entirely.
26 // The matrix transforms a rect to another rect, without mirrors or rotations, so both
27 // pre-and-post transform coordinates can be exactly represented as rects.
28 kSimpleRectStaysRect,
29 // The matrix transforms a rect to another rect, but may mirror or rotate the corners
30 // relative to each other. This means that the post-transformed rect completely fills
31 // that space.
32 kRectStaysRect,
33 // The matrix transform may have skew or rotation, so a mapped rect does not fill space,
34 // but there is no need to perform perspective division or w-plane clipping. This also
35 // includes orthographic projections.
36 kAffine,
37 // The matrix includes perspective and requires further projection to 2D, so care must be
38 // taken when w is less than or near 0, and homogeneous division and perspective-correct
39 // interpolation are needed when rendering.
41 // The matrix is not invertible or not finite, so should not be used to draw.
43 };
@ kInvalid
constexpr std::array< float, 9 > kIdentity

Constructor & Destructor Documentation

◆ Transform() [1/2]

skgpu::graphite::Transform::Transform ( const SkM44 m)
explicit

Definition at line 69 of file Transform.cpp.

69 : fM(m) {
70 static constexpr SkV4 kNoPerspective = {0.f, 0.f, 0.f, 1.f};
71 static constexpr SkV4 kNoZ = {0.f, 0.f, 1.f, 0.f};
72 if (m.row(3) != kNoPerspective) {
73 // Perspective matrices will have per-location scale factors calculated, so cached scale
74 // factors will not be used.
75 if (m.invert(&fInvM)) {
76 fType = Type::kPerspective;
77 } else {
78 fType = Type::kInvalid;
79 }
80 return;
81 } else if (m.col(2) != kNoZ || m.row(2) != kNoZ) {
82 // Orthographic matrices are lumped into the kAffine type although we use SkM44::invert()
83 // instead of taking short cuts.
84 if (m.invert(&fInvM)) {
85 fType = Type::kAffine;
86 // These scale factors are valid for the case where Z=0, which is the case for all
87 // local geometry that's drawn.
88 std::tie(fMinScaleFactor, fMaxScaleFactor) = compute_svd(m.rc(0,0), m.rc(0,1),
89 m.rc(1,0), m.rc(1,1));
90 } else {
91 fType = Type::kInvalid;
92 }
93 return;
94 }
95
96 // [sx kx 0 tx]
97 // At this point, we know that m is of the form [ky sy 0 ty]
98 // [0 0 1 0 ]
99 // [0 0 0 1 ]
100 // Other than kIdentity, none of the types depend on (tx, ty). The remaining types are
101 // identified by considering the upper 2x2 (tx and ty are still used to compute the inverse).
102 const float sx = m.rc(0, 0);
103 const float sy = m.rc(1, 1);
104 const float kx = m.rc(0, 1);
105 const float ky = m.rc(1, 0);
106 const float tx = m.rc(0, 3);
107 const float ty = m.rc(1, 3);
108 if (kx == 0.f && ky == 0.f) {
109 // 2x2 is a diagonal matrix
110 if (sx == 0.f || sy == 0.f) {
111 // Not invertible
112 fType = Type::kInvalid;
113 } else if (sx == 1.f && sy == 1.f && tx == 0.f && ty == 0.f) {
114 fType = Type::kIdentity;
115 fInvM.setIdentity();
116 } else {
117 const float ix = 1.f / sx;
118 const float iy = 1.f / sy;
119 fType = sx > 0.f && sy > 0.f ? Type::kSimpleRectStaysRect
121 fInvM = SkM44(ix, 0.f, 0.f, -ix*tx,
122 0.f, iy, 0.f, -iy*ty,
123 0.f, 0.f, 1.f, 0.f,
124 0.f, 0.f, 0.f, 1.f);
125 std::tie(fMinScaleFactor, fMaxScaleFactor) = sort_scale(sx, sy);
126 }
127 } else if (sx == 0.f && sy == 0.f) {
128 // 2x2 is an anti-diagonal matrix and represents a 90 or 270 degree rotation plus optional
129 // scale and translate.
130 if (kx == 0.f || ky == 0.f) {
131 // Not invertible
132 fType = Type::kInvalid;
133 } else {
134 const float ix = 1.f / kx;
135 const float iy = 1.f / ky;
136 fType = Type::kRectStaysRect;
137 fInvM = SkM44(0.f, iy, 0.f, -iy*ty,
138 ix, 0.f, 0.f, -ix*tx,
139 0.f, 0.f, 1.f, 0.f,
140 0.f, 0.f, 0.f, 1.f);
141 std::tie(fMinScaleFactor, fMaxScaleFactor) = sort_scale(kx, ky);
142 }
143 } else {
144 // Invert just the upper 2x2 and derive inverse translation from that
145 float upper[4] = {sx, ky, kx, sy}; // col-major
146 float invUpper[4];
147 if (SkInvert2x2Matrix(upper, invUpper) == 0.f) {
148 // 2x2 was not invertible, so the original matrix won't be invertible either
149 fType = Type::kInvalid;
150 } else {
151 fType = Type::kAffine;
152 fInvM = SkM44(invUpper[0], invUpper[2], 0.f, -invUpper[0]*tx - invUpper[2]*ty,
153 invUpper[1], invUpper[3], 0.f, -invUpper[1]*tx - invUpper[3]*ty,
154 0.f, 0.f, 1.f, 0.f,
155 0.f, 0.f, 0.f, 1.f);
156 std::tie(fMinScaleFactor, fMaxScaleFactor) = compute_svd(sx, kx, ky, sy);
157 }
158 }
159}
SkScalar SkInvert2x2Matrix(const SkScalar inMatrix[4], SkScalar outMatrix[4])
Definition: SkM44.h:150
SkM44 & setIdentity()
Definition: SkM44.h:293
Definition: SkM44.h:98

◆ Transform() [2/2]

skgpu::graphite::Transform::Transform ( const Transform t)
default

Member Function Documentation

◆ concat() [1/2]

Transform skgpu::graphite::Transform::concat ( const SkM44 t) const
inline

Definition at line 129 of file Transform_graphite.h.

129 {
130 SkASSERT(this->valid());
131 return Transform(fM * t);
132 }
#define SkASSERT(cond)
Definition: SkAssert.h:116
Transform(const SkM44 &m)
Definition: Transform.cpp:69

◆ concat() [2/2]

Transform skgpu::graphite::Transform::concat ( const Transform t) const
inline

Definition at line 125 of file Transform_graphite.h.

125 {
126 SkASSERT(this->valid());
127 return Transform(fM * t.fM);
128 }

◆ concatInverse() [1/2]

Transform skgpu::graphite::Transform::concatInverse ( const SkM44 t) const
inline

Definition at line 139 of file Transform_graphite.h.

139 {
140 SkASSERT(this->valid());
141 // Saves a multiply compared to inverting just 't' and calculating both fM*t^-1 and t*fInvM
142 // (t * this^-1)^-1 = this * t^-1
143 return Inverse(Transform(t * fInvM));
144 }
static Transform Inverse(const Transform &t)

◆ concatInverse() [2/2]

Transform skgpu::graphite::Transform::concatInverse ( const Transform t) const
inline

Definition at line 135 of file Transform_graphite.h.

135 {
136 SkASSERT(this->valid());
137 return Transform(fM * t.fInvM);
138 }

◆ Identity()

static constexpr Transform skgpu::graphite::Transform::Identity ( )
inlinestaticconstexpr

Definition at line 48 of file Transform_graphite.h.

48 {
49 return Transform(SkM44(), SkM44(), Type::kIdentity, 1.f, 1.f);
50 }

◆ Invalid()

static constexpr Transform skgpu::graphite::Transform::Invalid ( )
inlinestaticconstexpr

Definition at line 51 of file Transform_graphite.h.

51 {
53 Type::kInvalid, 1.f, 1.f);
54 }
@ kNaN_Constructor
Definition: SkM44.h:172

◆ inverse()

const SkM44 & skgpu::graphite::Transform::inverse ( ) const
inline

Definition at line 82 of file Transform_graphite.h.

82{ return fInvM; }

◆ Inverse()

static Transform skgpu::graphite::Transform::Inverse ( const Transform t)
inlinestatic

Definition at line 67 of file Transform_graphite.h.

67 {
68 return Transform(t.fInvM, t.fM, t.fType, 1.f / t.fMaxScaleFactor, 1.f / t.fMinScaleFactor);
69 }

◆ inverseMapPoints()

void skgpu::graphite::Transform::inverseMapPoints ( const SkV4 deviceIn,
SkV4 localOut,
int  count 
) const

Definition at line 284 of file Transform.cpp.

284 {
285 SkASSERT(this->valid());
286 return map_points(fInvM, deviceIn, localOut, count);
287}
int count
Definition: FontMgrTest.cpp:50

◆ inverseMapRect()

Rect skgpu::graphite::Transform::inverseMapRect ( const Rect rect) const

Definition at line 248 of file Transform.cpp.

248 {
249 SkASSERT(this->valid());
250 if (fType == Type::kIdentity) {
251 return rect;
252 }
253 return map_rect(fInvM, rect);
254}
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350

◆ localAARadius()

float skgpu::graphite::Transform::localAARadius ( const Rect bounds) const

Definition at line 213 of file Transform.cpp.

213 {
214 SkASSERT(this->valid());
215
216 float min;
217 if (fType < Type::kPerspective) {
218 // The scale factor is constant
219 min = fMinScaleFactor;
220 } else {
221 // Calculate the minimum scale factor over the 4 corners of the bounding box
222 float tl = std::get<0>(this->scaleFactors(SkV2{bounds.left(), bounds.top()}));
223 float tr = std::get<0>(this->scaleFactors(SkV2{bounds.right(), bounds.top()}));
224 float br = std::get<0>(this->scaleFactors(SkV2{bounds.right(), bounds.bot()}));
225 float bl = std::get<0>(this->scaleFactors(SkV2{bounds.left(), bounds.bot()}));
226 min = std::min(std::min(tl, tr), std::min(br, bl));
227 }
228
229 // Moving 1 from 'p' before transforming will move at least 'min' and at most 'max' from
230 // the transformed point. Thus moving between [1/max, 1/min] pre-transformation means post
231 // transformation moves between [1,max/min] so using 1/min as the local AA radius ensures that
232 // the post-transformed point is at least 1px away from the original.
233 float aaRadius = sk_ieee_float_divide(1.f, min);
234 if (SkIsFinite(aaRadius)) {
235 return aaRadius;
236 } else {
237 return SK_FloatInfinity;
238 }
239}
constexpr float SK_FloatInfinity
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
std::pair< float, float > scaleFactors(const SkV2 &p) const
Definition: Transform.cpp:161
static float min(float r, float g, float b)
Definition: hsl.cpp:48
Optional< SkRect > bounds
Definition: SkRecords.h:189
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
Definition: SkM44.h:19

◆ mapPoints() [1/3]

void skgpu::graphite::Transform::mapPoints ( const Rect localRect,
SkV4  deviceOut[4] 
) const

Definition at line 256 of file Transform.cpp.

256 {
257 SkASSERT(this->valid());
258 SkV2 localCorners[4] = {{localRect.left(), localRect.top()},
259 {localRect.right(), localRect.top()},
260 {localRect.right(), localRect.bot()},
261 {localRect.left(), localRect.bot()}};
262 this->mapPoints(localCorners, deviceOut, 4);
263}
void mapPoints(const Rect &localRect, SkV4 deviceOut[4]) const
Definition: Transform.cpp:256

◆ mapPoints() [2/3]

void skgpu::graphite::Transform::mapPoints ( const SkV2 localIn,
SkV4 deviceOut,
int  count 
) const

Definition at line 265 of file Transform.cpp.

265 {
266 SkASSERT(this->valid());
267 // TODO: These maybe should go into SkM44, since bulk point mapping seems generally useful
270 // skip c2 since localIn's z is assumed to be 0
272
273 for (int i = 0; i < count; ++i) {
274 auto p = c0 * localIn[i].x + c1 * localIn[i].y /* + c2*0.f */ + c3 /* *1.f */;
275 p.store(deviceOut + i);
276 }
277}
static const SkScalar * M44ColMajor(const SkM44 &m)
Definition: SkMatrixPriv.h:185
float x
Definition: SkM44.h:20
float y
Definition: SkM44.h:20
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109

◆ mapPoints() [3/3]

void skgpu::graphite::Transform::mapPoints ( const SkV4 localIn,
SkV4 deviceOut,
int  count 
) const

Definition at line 279 of file Transform.cpp.

279 {
280 SkASSERT(this->valid());
281 return map_points(fM, localIn, deviceOut, count);
282}

◆ mapRect()

Rect skgpu::graphite::Transform::mapRect ( const Rect rect) const

Definition at line 241 of file Transform.cpp.

241 {
242 SkASSERT(this->valid());
243 if (fType == Type::kIdentity) {
244 return rect;
245 }
246 return map_rect(fM, rect);
247}

◆ matrix()

const SkM44 & skgpu::graphite::Transform::matrix ( ) const
inline

Definition at line 81 of file Transform_graphite.h.

81{ return fM; }

◆ maxScaleFactor()

float skgpu::graphite::Transform::maxScaleFactor ( ) const
inline

Definition at line 93 of file Transform_graphite.h.

93 {
94 SkASSERT(this->valid());
95 return fMaxScaleFactor;
96 }

◆ operator const SkM44 &()

skgpu::graphite::Transform::operator const SkM44 & ( ) const
inline

Definition at line 73 of file Transform_graphite.h.

73{ return fM; }

◆ operator SkMatrix()

skgpu::graphite::Transform::operator SkMatrix ( ) const
inline

Definition at line 74 of file Transform_graphite.h.

74{ return fM.asM33(); }
SkMatrix asM33() const
Definition: SkM44.h:409

◆ operator!=()

bool skgpu::graphite::Transform::operator!= ( const Transform t) const
inline

Definition at line 76 of file Transform_graphite.h.

76{ return !(*this == t); }

◆ operator=()

Transform & skgpu::graphite::Transform::operator= ( const Transform t)
default

◆ operator==()

bool skgpu::graphite::Transform::operator== ( const Transform t) const
inline

Definition at line 77 of file Transform_graphite.h.

77 {
78 return this->valid() == t.valid() && (!this->valid() || fM == t.fM);
79 }

◆ postTranslate()

Transform skgpu::graphite::Transform::postTranslate ( float  x,
float  y 
) const
inline

Definition at line 120 of file Transform_graphite.h.

120 {
121 return Translate(x, y).concat(*this);
122 }
static Transform Translate(float x, float y)
Transform concat(const Transform &t) const
double y
double x

◆ preTranslate()

Transform skgpu::graphite::Transform::preTranslate ( float  x,
float  y 
) const
inline

Definition at line 117 of file Transform_graphite.h.

117 {
118 return this->concat(SkM44::Translate(x, y));
119 }
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition: SkM44.h:225

◆ scaleFactors()

std::pair< float, float > skgpu::graphite::Transform::scaleFactors ( const SkV2 p) const

Definition at line 161 of file Transform.cpp.

161 {
162 SkASSERT(this->valid());
163 if (fType < Type::kPerspective) {
164 return {fMinScaleFactor, fMaxScaleFactor};
165 }
166
167 // [m00 m01 * m03] [f(u,v)]
168 // Assuming M = [m10 m11 * m13], define the projected p'(u,v) = [g(u,v)] where
169 // [ * * * * ]
170 // [m30 m31 * m33]
171 // [x] [u]
172 // f(u,v) = x(u,v) / w(u,v), g(u,v) = y(u,v) / w(u,v) and [y] = M*[v]
173 // [*] = [0]
174 // [w] [1]
175 //
176 // x(u,v) = m00*u + m01*v + m03
177 // y(u,v) = m10*u + m11*v + m13
178 // w(u,v) = m30*u + m31*v + m33
179 //
180 // dx/du = m00, dx/dv = m01,
181 // dy/du = m10, dy/dv = m11
182 // dw/du = m30, dw/dv = m31
183 //
184 // df/du = (dx/du*w - x*dw/du)/w^2 = (m00*w - m30*x)/w^2 = (m00 - m30*f)/w
185 // df/dv = (dx/dv*w - x*dw/dv)/w^2 = (m01*w - m31*x)/w^2 = (m01 - m31*f)/w
186 // dg/du = (dy/du*w - y*dw/du)/w^2 = (m10*w - m30*y)/w^2 = (m10 - m30*g)/w
187 // dg/dv = (dy/dv*w - y*dw/du)/w^2 = (m11*w - m31*y)/w^2 = (m11 - m31*g)/w
188 //
189 // Singular values of [df/du df/dv] define perspective correct minimum and maximum scale factors
190 // [dg/du dg/dv]
191 // for M evaluated at (u,v)
192 SkV4 devP = fM.map(p.x, p.y, 0.f, 1.f);
193
194 const float dxdu = fM.rc(0,0);
195 const float dxdv = fM.rc(0,1);
196 const float dydu = fM.rc(1,0);
197 const float dydv = fM.rc(1,1);
198 const float dwdu = fM.rc(3,0);
199 const float dwdv = fM.rc(3,1);
200
201 float invW2 = sk_ieee_float_divide(1.f, (devP.w * devP.w));
202 // non-persp has invW2 = 1, devP.w = 1, dwdu = 0, dwdv = 0
203 float dfdu = (devP.w*dxdu - devP.x*dwdu) * invW2; // non-persp -> dxdu -> m00
204 float dfdv = (devP.w*dxdv - devP.x*dwdv) * invW2; // non-persp -> dxdv -> m01
205 float dgdu = (devP.w*dydu - devP.y*dwdu) * invW2; // non-persp -> dydu -> m10
206 float dgdv = (devP.w*dydv - devP.y*dwdv) * invW2; // non-persp -> dydv -> m11
207
208 // no-persp, these are the singular values of [m00,m01][m10,m11], which was already calculated
209 // in get_matrix_info.
210 return compute_svd(dfdu, dfdv, dgdu, dgdv);
211}
SkV4 map(float x, float y, float z, float w) const
Definition: SkM44.cpp:129
SkScalar rc(int r, int c) const
Definition: SkM44.h:261
float w
Definition: SkM44.h:99
float y
Definition: SkM44.h:99
float x
Definition: SkM44.h:99

◆ Translate()

static Transform skgpu::graphite::Transform::Translate ( float  x,
float  y 
)
inlinestatic

Definition at line 56 of file Transform_graphite.h.

56 {
57 if (x == 0.f && y == 0.f) {
58 return Identity();
59 } else if (SkIsFinite(x, y)) {
62 } else {
63 return Invalid();
64 }
65 }
static constexpr Transform Invalid()
static constexpr Transform Identity()

◆ type()

Type skgpu::graphite::Transform::type ( ) const
inline

Definition at line 84 of file Transform_graphite.h.

84{ return fType; }

◆ valid()

bool skgpu::graphite::Transform::valid ( ) const
inline

Definition at line 85 of file Transform_graphite.h.

85{ return fType != Type::kInvalid; }

The documentation for this class was generated from the following files: