1 /*
2 * Copyright 2021 Google LLC
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 "experimental/graphite/src/geom/Transform_graphite.h"
9
10 #include "experimental/graphite/src/geom/Rect.h"
11 #include "experimental/graphite/src/geom/VectorTypes.h"
12 #include "src/core/SkMatrixPriv.h"
13
14 namespace skgpu {
15
16 namespace {
17
map_rect(const SkM44 & m,const Rect & r)18 Rect map_rect(const SkM44& m, const Rect& r) {
19 // TODO: Can Rect's (l,t,-r,-b) structure be used to optimize mapRect?
20 // TODO: Can take this opportunity to implement 100% accurate perspective plane clipping since
21 // it doesn't have to match raster/ganesh rendering behavior.
22 return SkMatrixPriv::MapRect(m, r.asSkRect());
23 }
24
25 } // anonymous namespace
26
Transform(const SkM44 & m)27 Transform::Transform(const SkM44& m)
28 : fM(m) {
29 if (fM.invert(&fInvM)) {
30 // TODO: actually detect these
31 fType = (fM == SkM44()) ? Type::kIdentity : Type::kPerspective;
32 fScale = {1.f, 1.f};
33 } else {
34 fType = Type::kInvalid;
35 fInvM = SkM44();
36 fScale = {1.f, 1.f};
37 }
38 }
39
operator ==(const Transform & t) const40 bool Transform::operator==(const Transform& t) const {
41 // Checking fM should be sufficient as all other values are computed from it.
42 SkASSERT(fM != t.fM || (fInvM == t.fInvM && fType == t.fType && fScale == t.fScale));
43 return fM == t.fM;
44 }
45
mapRect(const Rect & rect) const46 Rect Transform::mapRect(const Rect& rect) const { return map_rect(fM, rect); }
inverseMapRect(const Rect & rect) const47 Rect Transform::inverseMapRect(const Rect& rect) const { return map_rect(fInvM, rect); }
48
mapPoints(const Rect & localRect,SkV4 deviceOut[4]) const49 void Transform::mapPoints(const Rect& localRect, SkV4 deviceOut[4]) const {
50 SkV2 localCorners[4] = {{localRect.left(), localRect.top()},
51 {localRect.right(), localRect.top()},
52 {localRect.right(), localRect.bot()},
53 {localRect.left(), localRect.bot()}};
54 this->mapPoints(localCorners, deviceOut, 4);
55 }
56
mapPoints(const SkV2 * localIn,SkV4 * deviceOut,int count) const57 void Transform::mapPoints(const SkV2* localIn, SkV4* deviceOut, int count) const {
58 // TODO: These maybe should go into SkM44, since bulk point mapping seems generally useful
59 float4 c0 = float4::Load(SkMatrixPriv::M44ColMajor(fM) + 0);
60 float4 c1 = float4::Load(SkMatrixPriv::M44ColMajor(fM) + 4);
61 // skip c2 since localIn's z is assumed to be 0
62 float4 c3 = float4::Load(SkMatrixPriv::M44ColMajor(fM) + 12);
63
64 for (int i = 0; i < count; ++i) {
65 float4 p = c0 * localIn[i].x + c1 * localIn[i].y /* + c2*0.f */ + c3 /* *1.f */;
66 p.store(deviceOut + i);
67 }
68 }
69
70 } // namespace skgpu
71