Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_GEOM_SPSIMD_H_
25 : #define STAPPLER_GEOM_SPSIMD_H_
26 :
27 : #include "SPCommon.h"
28 :
29 : #define SP_SIMD_DEBUG 0
30 :
31 : #if SP_SIMD_DEBUG
32 : #define SP_ATTR_OPTIMIZE_FN
33 : #define SP_ATTR_OPTIMIZE_INLINE_FN
34 : #else
35 : // mostly to debug SIMD in ASM, maybe disable for NDEBUG?
36 : #if __clang__
37 : #define SP_ATTR_OPTIMIZE_FN
38 : #define SP_ATTR_OPTIMIZE_INLINE_FN __attribute__((always_inline))
39 : #else
40 : #define SP_ATTR_OPTIMIZE_FN __attribute__((optimize(3)))
41 : #define SP_ATTR_OPTIMIZE_INLINE_FN __attribute__((optimize(3),always_inline))
42 : #endif
43 : #endif
44 :
45 : #define SP_GEOM_DEFAULT_SIMD_SSE 1
46 : #define SP_GEOM_DEFAULT_SIMD_NEON 2
47 : #define SP_GEOM_DEFAULT_SIMD_NEON64 3
48 :
49 : #if __SSE__
50 : #define SP_GEOM_DEFAULT_SIMD SP_GEOM_DEFAULT_SIMD_SSE
51 : #define SP_GEOM_DEFAULT_SIMD_NAMESPACE sse
52 : #elif __arm__
53 : #define SP_GEOM_DEFAULT_SIMD SP_GEOM_DEFAULT_SIMD_NEON
54 : #define SP_GEOM_DEFAULT_SIMD_NAMESPACE neon
55 : #elif __aarch64__
56 : #define SP_GEOM_DEFAULT_SIMD SP_GEOM_DEFAULT_SIMD_NEON64
57 : #define SP_GEOM_DEFAULT_SIMD_NAMESPACE neon64
58 : #else
59 : #define SP_GEOM_DEFAULT_SIMD SP_GEOM_DEFAULT_SIMD_SSE
60 : #define SP_GEOM_DEFAULT_SIMD_NAMESPACE sse
61 : #endif
62 :
63 : #if SP_GEOM_DEFAULT_SIMD == SP_GEOM_DEFAULT_SIMD_NEON
64 : #include "simde/arm/neon.h"
65 : #include "simde/x86/sse.h"
66 : #else
67 : #include "simde/x86/sse.h"
68 : #endif
69 :
70 : // Defined by build system
71 : // If SP_DEDICATED_SIMD is defined, replacements for SIMD on other platforms is not available
72 : // If SP_DEDICATED_SIMD is not defined, you can use simd::neon on sse or simd::sse on NEON
73 : #ifdef SP_DEDICATED_SIMD
74 : #if SP_GEOM_DEFAULT_SIMD == SP_GEOM_DEFAULT_SIMD_NEON
75 : #include "SPSIMD_Neon.h"
76 : #elif SP_GEOM_DEFAULT_SIMD == SP_GEOM_DEFAULT_SIMD_NEON64
77 : #include "SPSIMD_Neon64.h"
78 : #else
79 : #include "SPSIMD_Sse.h"
80 : #endif
81 : #else
82 : #include "SPSIMD_Sse.h"
83 : #include "SPSIMD_Neon.h"
84 : #include "SPSIMD_Neon64.h"
85 : #endif
86 :
87 :
88 : namespace STAPPLER_VERSIONIZED stappler::simd {
89 :
90 : using f32x4 = SP_GEOM_DEFAULT_SIMD_NAMESPACE::f32x4;
91 :
92 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 load(float v1, float v2, float v3, float v4) {
93 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::load(v1, v2, v3, v4);
94 : }
95 :
96 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 load(const float v[4]) {
97 141700 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::load(v);
98 : }
99 :
100 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 load(float v) {
101 98453 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::load(v);
102 : }
103 :
104 : SP_ATTR_OPTIMIZE_INLINE_FN inline void store(float target[4], const f32x4 &v) {
105 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::store(target, v);
106 141337 : }
107 :
108 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 mul(const f32x4 &v1, const f32x4 &v2) {
109 98478 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::mul(v1, v2);
110 : }
111 :
112 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 div(const f32x4 &v1, const f32x4 &v2) {
113 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::div(v1, v2);
114 : }
115 :
116 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 add(const f32x4 &v1, const f32x4 &v2) {
117 43585 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::add(v1, v2);
118 : }
119 :
120 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 sub(const f32x4 &v1, const f32x4 &v2) {
121 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::sub(v1, v2);
122 : }
123 :
124 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 rsqrt(const f32x4 &v) {
125 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::rsqrt(v);
126 : }
127 :
128 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 load1(float v) {
129 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::load1(v);
130 : }
131 :
132 : SP_ATTR_OPTIMIZE_INLINE_FN inline void store1(float *target, const f32x4 &v) {
133 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::store1(target, v);
134 : }
135 :
136 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 mul1(const f32x4 &v1, const f32x4 &v2) {
137 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::mul1(v1, v2);
138 : }
139 :
140 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 add1(const f32x4 &v1, const f32x4 &v2) {
141 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::add1(v1, v2);
142 : }
143 :
144 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 sub1(const f32x4 &v1, const f32x4 &v2) {
145 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::sub1(v1, v2);
146 : }
147 :
148 : SP_ATTR_OPTIMIZE_INLINE_FN inline f32x4 rsqrt1(const f32x4 &v) {
149 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::rsqrt1(v);
150 : }
151 :
152 : SP_ATTR_OPTIMIZE_INLINE_FN inline void add(const float a[4], const float b[4], float dst[4]) {
153 : store(dst, add(load(a), load(b)));
154 50 : }
155 :
156 : SP_ATTR_OPTIMIZE_INLINE_FN inline void add(const float a[4], const float &b, float dst[4]) {
157 : store(dst, add(load(a), load(b)));
158 : }
159 :
160 : SP_ATTR_OPTIMIZE_INLINE_FN inline void sub(const float a[4], const float b[4], float dst[4]) {
161 : store(dst, sub(load(a), load(b)));
162 : }
163 :
164 : SP_ATTR_OPTIMIZE_INLINE_FN inline void sub(const float a[4], const float &b, float dst[4]) {
165 : store(dst, sub(load(a), load(b)));
166 : }
167 :
168 : SP_ATTR_OPTIMIZE_INLINE_FN inline void multiply(const float a[4], const float b[4], float dst[4]) {
169 : store(dst, mul(load(a), load(b)));
170 30692772 : }
171 :
172 : SP_ATTR_OPTIMIZE_INLINE_FN inline void multiply(const float a[4], const float &b, float dst[4]) {
173 : store(dst, mul(load(a), load(b)));
174 : }
175 :
176 : SP_ATTR_OPTIMIZE_INLINE_FN inline void divide(const float a[4], const float b[4], float dst[4]) {
177 : store(dst, div(load(a), load(b)));
178 : }
179 :
180 : SP_ATTR_OPTIMIZE_INLINE_FN inline void divide(const float a[4], const float &b, float dst[4]) {
181 : store(dst, div(load(a), load(b)));
182 : }
183 :
184 : SP_ATTR_OPTIMIZE_INLINE_FN inline void addMat4Scalar(const float m[16], float scalar, float dst[16]) {
185 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::addMat4Scalar(m, scalar, dst);
186 : }
187 :
188 : SP_ATTR_OPTIMIZE_INLINE_FN inline void addMat4(const float m1[16], const float m2[16], float dst[16]) {
189 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::addMat4(m1, m2, dst);
190 : }
191 :
192 : SP_ATTR_OPTIMIZE_INLINE_FN inline void subtractMat4(const float m1[16], const float m2[16], float dst[16]) {
193 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::subtractMat4(m1, m2, dst);
194 : }
195 :
196 : SP_ATTR_OPTIMIZE_INLINE_FN inline void multiplyMat4Scalar(const float m[16], float scalar, float dst[16]) {
197 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::multiplyMat4Scalar(m, scalar, dst);
198 82100 : }
199 :
200 : SP_ATTR_OPTIMIZE_INLINE_FN inline void multiplyMat4(const float m1[16], const float m2[16], float dst[16]) {
201 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::multiplyMat4(m1, m2, dst);
202 2697348 : }
203 :
204 : SP_ATTR_OPTIMIZE_INLINE_FN inline void negateMat4(const float m[16], float dst[16]) {
205 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::negateMat4(m, dst);
206 : }
207 :
208 : SP_ATTR_OPTIMIZE_INLINE_FN inline void transposeMat4(const float m[16], float dst[16]) {
209 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::transposeMat4(m, dst);
210 : }
211 :
212 : SP_ATTR_OPTIMIZE_INLINE_FN inline void transformVec4Components(const float m[16], float x, float y, float z, float w, float dst[4]) {
213 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::transformVec4Components(m, x, y, z, w, dst);
214 7009 : }
215 :
216 : SP_ATTR_OPTIMIZE_INLINE_FN inline void transformVec4(const float m[16], const float v[4], float dst[4]) {
217 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::transformVec4(m, v, dst);
218 : }
219 :
220 : SP_ATTR_OPTIMIZE_INLINE_FN inline void crossVec3(const float v1[3], const float v2[3], float dst[3]) {
221 : SP_GEOM_DEFAULT_SIMD_NAMESPACE::crossVec3(v1, v2, dst);
222 200 : }
223 :
224 : // input for test A->B vs C->D (ax, ay, bx, by), (cx, cy, dx, dy)
225 : SP_ATTR_OPTIMIZE_INLINE_FN inline bool isVec2BboxIntersects(const f32x4 & v1, const f32x4 & v2, f32x4 &isect) {
226 : return SP_GEOM_DEFAULT_SIMD_NAMESPACE::isVec2BboxIntersects(v1, v2, isect);
227 : }
228 :
229 : }
230 :
231 : #endif /* STAPPLER_GEOM_SPSIMD_H_ */
|