/src/skia/src/gpu/tessellate/CullTest.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2021 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 | | #ifndef skgpu_tessellate_CullTest_DEFINED |
9 | | #define skgpu_tessellate_CullTest_DEFINED |
10 | | |
11 | | #include "include/core/SkMatrix.h" |
12 | | #include "include/core/SkPoint.h" |
13 | | #include "include/core/SkRect.h" |
14 | | #include "include/private/base/SkAssert.h" |
15 | | #include "src/base/SkVx.h" |
16 | | |
17 | | namespace skgpu::tess { |
18 | | |
19 | | // This class determines whether the given local-space points will be contained in the cull bounds |
20 | | // post transform. For the versions that take >1 point, it returns whether any region of their |
21 | | // device-space bounding box will be in the cull bounds. |
22 | | // |
23 | | // NOTE: Our view matrix is not a normal matrix. M*p maps to the float4 [x, y, -x, -y] in device |
24 | | // space. We do this to aid in quick bounds calculations. The matrix also does not have a |
25 | | // translation element. Instead we unapply the translation to the cull bounds ahead of time. |
26 | | class CullTest { |
27 | | public: |
28 | | CullTest() = default; |
29 | | |
30 | 0 | CullTest(const SkRect& devCullBounds, const SkMatrix& m) { |
31 | 0 | this->set(devCullBounds, m); |
32 | 0 | } |
33 | | |
34 | 0 | void set(const SkRect& devCullBounds, const SkMatrix& m) { |
35 | 0 | SkASSERT(!m.hasPerspective()); |
36 | | // [fMatX, fMatY] maps path coordinates to the float4 [x, y, -x, -y] in device space. |
37 | 0 | fMatX = {m.getScaleX(), m.getSkewY(), -m.getScaleX(), -m.getSkewY()}; |
38 | 0 | fMatY = {m.getSkewX(), m.getScaleY(), -m.getSkewX(), -m.getScaleY()}; |
39 | | // Store the cull bounds as [l, t, -r, -b] for faster math. |
40 | | // Also subtract the matrix translate from the cull bounds ahead of time, rather than adding |
41 | | // it to every point every time we test. |
42 | 0 | fCullBounds = {devCullBounds.fLeft - m.getTranslateX(), |
43 | 0 | devCullBounds.fTop - m.getTranslateY(), |
44 | 0 | m.getTranslateX() - devCullBounds.fRight, |
45 | 0 | m.getTranslateY() - devCullBounds.fBottom}; |
46 | 0 | } Unexecuted instantiation: skgpu::tess::CullTest::set(SkRect const&, SkMatrix const&) Unexecuted instantiation: skgpu::tess::CullTest::set(SkRect const&, SkMatrix const&) |
47 | | |
48 | | // Returns whether M*p will be in the viewport. |
49 | 0 | bool isVisible(SkPoint p) const { |
50 | 0 | // devPt = [x, y, -x, -y] in device space. |
51 | 0 | auto devPt = fMatX*p.fX + fMatY*p.fY; |
52 | 0 | // i.e., l < x && t < y && r > x && b > y. |
53 | 0 | return all(fCullBounds < devPt); |
54 | 0 | } |
55 | | |
56 | | // Returns whether any region of the bounding box of M * p0..2 will be in the viewport. |
57 | 0 | bool areVisible3(const SkPoint p[3]) const { |
58 | | // Transform p0..2 to device space. |
59 | 0 | auto val0 = fMatY * p[0].fY; |
60 | 0 | auto val1 = fMatY * p[1].fY; |
61 | 0 | auto val2 = fMatY * p[2].fY; |
62 | 0 | val0 = fMatX*p[0].fX + val0; |
63 | 0 | val1 = fMatX*p[1].fX + val1; |
64 | 0 | val2 = fMatX*p[2].fX + val2; |
65 | | // At this point: valN = {xN, yN, -xN, -yN} in device space. |
66 | | |
67 | | // Find the device-space bounding box of p0..2. |
68 | 0 | val0 = max(val0, val1); |
69 | 0 | val0 = max(val0, val2); |
70 | | // At this point: val0 = [r, b, -l, -t] of the device-space bounding box of p0..2. |
71 | | |
72 | | // Does fCullBounds intersect the device-space bounding box of p0..2? |
73 | | // i.e., l0 < r1 && t0 < b1 && r0 > l1 && b0 > t1. |
74 | 0 | return all(fCullBounds < val0); |
75 | 0 | } |
76 | | |
77 | | // Returns whether any region of the bounding box of M * p0..3 will be in the viewport. |
78 | 0 | bool areVisible4(const SkPoint p[4]) const { |
79 | | // Transform p0..3 to device space. |
80 | 0 | auto val0 = fMatY * p[0].fY; |
81 | 0 | auto val1 = fMatY * p[1].fY; |
82 | 0 | auto val2 = fMatY * p[2].fY; |
83 | 0 | auto val3 = fMatY * p[3].fY; |
84 | 0 | val0 = fMatX*p[0].fX + val0; |
85 | 0 | val1 = fMatX*p[1].fX + val1; |
86 | 0 | val2 = fMatX*p[2].fX + val2; |
87 | 0 | val3 = fMatX*p[3].fX + val3; |
88 | | // At this point: valN = {xN, yN, -xN, -yN} in device space. |
89 | | |
90 | | // Find the device-space bounding box of p0..3. |
91 | 0 | val0 = max(val0, val1); |
92 | 0 | val2 = max(val2, val3); |
93 | 0 | val0 = max(val0, val2); |
94 | | // At this point: val0 = [r, b, -l, -t] of the device-space bounding box of p0..3. |
95 | | |
96 | | // Does fCullBounds intersect the device-space bounding box of p0..3? |
97 | | // i.e., l0 < r1 && t0 < b1 && r0 > l1 && b0 > t1. |
98 | 0 | return all(fCullBounds < val0); |
99 | 0 | } |
100 | | |
101 | | private: |
102 | | // [fMatX, fMatY] maps path coordinates to the float4 [x, y, -x, -y] in device space. |
103 | | skvx::float4 fMatX; |
104 | | skvx::float4 fMatY; |
105 | | skvx::float4 fCullBounds; // [l, t, -r, -b] |
106 | | }; |
107 | | |
108 | | } // namespace skgpu::tess |
109 | | |
110 | | #endif // skgpu_tessellate_CullTest_DEFINED |