RavEngine
Loading...
Searching...
No Matches
PxUnixNeonInlineAoS.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef PXFOUNDATION_PXUNIXNEONINLINEAOS_H
30#define PXFOUNDATION_PXUNIXNEONINLINEAOS_H
31
32#if !COMPILE_VECTOR_INTRINSICS
33#error Vector intrinsics should not be included when using scalar implementation.
34#endif
35
36namespace physx
37{
38namespace aos
39{
40
41// improved estimates
42#define VRECIPEQ recipq_newton<1>
43#define VRECIPE recip_newton<1>
44#define VRECIPSQRTEQ rsqrtq_newton<1>
45#define VRECIPSQRTE rsqrt_newton<1>
46
47// "exact"
48#define VRECIPQ recipq_newton<4>
49#if PX_SWITCH
50// StabilizationTests.AveragePoint needs more precision to succeed.
51#define VRECIP recip_newton<5>
52#else
53#define VRECIP recip_newton<4>
54#endif
55#define VRECIPSQRTQ rsqrtq_newton<4>
56#define VRECIPSQRT rsqrt_newton<4>
57
58#define VECMATH_AOS_EPSILON (1e-3f)
59
61//Test that Vec3V and FloatV are legal
63
64#define FLOAT_COMPONENTS_EQUAL_THRESHOLD 0.01f
65PX_FORCE_INLINE bool isValidFloatV(const FloatV a)
66{
67 /*
68 PX_ALIGN(16, PxF32) data[4];
69 vst1_f32(reinterpret_cast<float32_t*>(data), a);
70 return
71 PxU32* intData = reinterpret_cast<PxU32*>(data);
72 return intData[0] == intData[1];
73 */
74 PX_ALIGN(16, PxF32) data[4];
75 vst1_f32(reinterpret_cast<float32_t*>(data), a);
76 const float32_t x = data[0];
77 const float32_t y = data[1];
78
79 return (x == y);
80
81 /*if (PxAbs(x - y) < FLOAT_COMPONENTS_EQUAL_THRESHOLD)
82 {
83 return true;
84 }
85
86 if (PxAbs((x - y) / x) < FLOAT_COMPONENTS_EQUAL_THRESHOLD)
87 {
88 return true;
89 }
90
91 return false;*/
92}
93
94PX_FORCE_INLINE bool isValidVec3V(const Vec3V a)
95{
96 const float32_t w = vgetq_lane_f32(a, 3);
97 return (0.0f == w);
98 //const PxU32* intData = reinterpret_cast<const PxU32*>(&w);
99 //return *intData == 0;
100}
101
102PX_FORCE_INLINE bool isAligned16(const void* a)
103{
104 return(0 == (size_t(a) & 0x0f));
105}
106
107#if PX_DEBUG
108#define ASSERT_ISVALIDVEC3V(a) PX_ASSERT(isValidVec3V(a))
109#define ASSERT_ISVALIDFLOATV(a) PX_ASSERT(isValidFloatV(a))
110#define ASSERT_ISALIGNED16(a) PX_ASSERT(isAligned16(static_cast<const void*>(a)))
111#else
112#define ASSERT_ISVALIDVEC3V(a)
113#define ASSERT_ISVALIDFLOATV(a)
114#define ASSERT_ISALIGNED16(a)
115#endif
116
117namespace internalUnitNeonSimd
118{
119PX_FORCE_INLINE PxU32 BAllTrue4_R(const BoolV a)
120{
121 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
122 const uint16x4_t dLow = vmovn_u32(a);
123 const uint16x8_t combined = vcombine_u16(dLow, dHigh);
124 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
125 return PxU32(vget_lane_u32(finalReduce, 0) == 0xffffFFFF);
126}
127
128PX_FORCE_INLINE PxU32 BAllTrue3_R(const BoolV a)
129{
130 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
131 const uint16x4_t dLow = vmovn_u32(a);
132 const uint16x8_t combined = vcombine_u16(dLow, dHigh);
133 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
134 return PxU32((vget_lane_u32(finalReduce, 0) & 0xffFFff) == 0xffFFff);
135}
136
137PX_FORCE_INLINE PxU32 BAnyTrue4_R(const BoolV a)
138{
139 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
140 const uint16x4_t dLow = vmovn_u32(a);
141 const uint16x8_t combined = vcombine_u16(dLow, dHigh);
142 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
143 return PxU32(vget_lane_u32(finalReduce, 0) != 0x0);
144}
145
146PX_FORCE_INLINE PxU32 BAnyTrue3_R(const BoolV a)
147{
148 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
149 const uint16x4_t dLow = vmovn_u32(a);
150 const uint16x8_t combined = vcombine_u16(dLow, dHigh);
151 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
152 return PxU32((vget_lane_u32(finalReduce, 0) & 0xffFFff) != 0);
153}
154}
155
156namespace vecMathTests
157{
158// PT: this function returns an invalid Vec3V (W!=0.0f) just for unit-testing 'isValidVec3V'
159PX_FORCE_INLINE Vec3V getInvalidVec3V()
160{
161 PX_ALIGN(16, PxF32) data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
162 return V4LoadA(data);
163}
164
165PX_FORCE_INLINE bool allElementsEqualFloatV(const FloatV a, const FloatV b)
166{
167 ASSERT_ISVALIDFLOATV(a);
168 ASSERT_ISVALIDFLOATV(b);
169 return vget_lane_u32(vceq_f32(a, b), 0) != 0;
170}
171
172PX_FORCE_INLINE bool allElementsEqualVec3V(const Vec3V a, const Vec3V b)
173{
174 ASSERT_ISVALIDVEC3V(a);
175 ASSERT_ISVALIDVEC3V(b);
176 return V3AllEq(a, b) != 0;
177}
178
179PX_FORCE_INLINE bool allElementsEqualVec4V(const Vec4V a, const Vec4V b)
180{
181 return V4AllEq(a, b) != 0;
182}
183
184PX_FORCE_INLINE bool allElementsEqualBoolV(const BoolV a, const BoolV b)
185{
186 return internalUnitNeonSimd::BAllTrue4_R(vceqq_u32(a, b)) != 0;
187}
188
189PX_FORCE_INLINE PxU32 V4U32AllEq(const VecU32V a, const VecU32V b)
190{
191 return internalUnitNeonSimd::BAllTrue4_R(V4IsEqU32(a, b));
192}
193
194PX_FORCE_INLINE bool allElementsEqualVecU32V(const VecU32V a, const VecU32V b)
195{
196 return V4U32AllEq(a, b) != 0;
197}
198
199PX_FORCE_INLINE BoolV V4IsEqI32(const VecI32V a, const VecI32V b)
200{
201 return vceqq_s32(a, b);
202}
203
204PX_FORCE_INLINE PxU32 V4I32AllEq(const VecI32V a, const VecI32V b)
205{
206 return internalUnitNeonSimd::BAllTrue4_R(V4IsEqI32(a, b));
207}
208
209PX_FORCE_INLINE bool allElementsEqualVecI32V(const VecI32V a, const VecI32V b)
210{
211 return V4I32AllEq(a, b) != 0;
212}
213
214PX_FORCE_INLINE bool allElementsNearEqualFloatV(const FloatV a, const FloatV b)
215{
216 ASSERT_ISVALIDFLOATV(a);
217 ASSERT_ISVALIDFLOATV(b);
218
219 const float32x2_t c = vsub_f32(a, b);
220 const float32x2_t error = vdup_n_f32(VECMATH_AOS_EPSILON);
221// absolute compare abs(error) > abs(c)
222 const uint32x2_t greater = vcagt_f32(error, c);
223 const uint32x2_t min = vpmin_u32(greater, greater);
224 return vget_lane_u32(min, 0) != 0x0;
225}
226
227PX_FORCE_INLINE bool allElementsNearEqualVec3V(const Vec3V a, const Vec3V b)
228{
229 ASSERT_ISVALIDVEC3V(a);
230 ASSERT_ISVALIDVEC3V(b);
231 const float32x4_t c = vsubq_f32(a, b);
232 const float32x4_t error = vdupq_n_f32(VECMATH_AOS_EPSILON);
233// absolute compare abs(error) > abs(c)
234 const uint32x4_t greater = vcagtq_f32(error, c);
235 return internalUnitNeonSimd::BAllTrue3_R(greater) != 0;
236}
237
238PX_FORCE_INLINE bool allElementsNearEqualVec4V(const Vec4V a, const Vec4V b)
239{
240 const float32x4_t c = vsubq_f32(a, b);
241 const float32x4_t error = vdupq_n_f32(VECMATH_AOS_EPSILON);
242// absolute compare abs(error) > abs(c)
243 const uint32x4_t greater = vcagtq_f32(error, c);
244 return internalUnitNeonSimd::BAllTrue4_R(greater) != 0x0;
245}
246}
247
248#if 0 // debugging printfs
249#include <stdio.h>
250PX_FORCE_INLINE void printVec(const float32x4_t& v, const char* name)
251{
252 PX_ALIGN(16, float32_t) data[4];
253 vst1q_f32(data, v);
254 printf("%s: (%f, %f, %f, %f)\n", name, data[0], data[1], data[2], data[3]);
255}
256
257PX_FORCE_INLINE void printVec(const float32x2_t& v, const char* name)
258{
259 PX_ALIGN(16, float32_t) data[2];
260 vst1_f32(data, v);
261 printf("%s: (%f, %f)\n", name, data[0], data[1]);
262}
263
264PX_FORCE_INLINE void printVec(const uint32x4_t& v, const char* name)
265{
266 PX_ALIGN(16, uint32_t) data[4];
267 vst1q_u32(data, v);
268 printf("%s: (0x%x, 0x%x, 0x%x, 0x%x)\n", name, data[0], data[1], data[2], data[3]);
269}
270
271PX_FORCE_INLINE void printVec(const uint16x8_t& v, const char* name)
272{
273 PX_ALIGN(16, uint16_t) data[8];
274 vst1q_u16(data, v);
275 printf("%s: (0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", name, data[0], data[1], data[2], data[3],
276 data[4], data[5], data[6], data[7]);
277}
278
279PX_FORCE_INLINE void printVec(const int32x4_t& v, const char* name)
280{
281 PX_ALIGN(16, int32_t) data[4];
282 vst1q_s32(data, v);
283 printf("%s: (0x%x, 0x%x, 0x%x, 0x%x)\n", name, data[0], data[1], data[2], data[3]);
284}
285
286PX_FORCE_INLINE void printVec(const int16x8_t& v, const char* name)
287{
288 PX_ALIGN(16, int16_t) data[8];
289 vst1q_s16(data, v);
290 printf("%s: (0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", name, data[0], data[1], data[2], data[3],
291 data[4], data[5], data[6], data[7]);
292}
293
294PX_FORCE_INLINE void printVec(const uint16x4_t& v, const char* name)
295{
296 PX_ALIGN(16, uint16_t) data[4];
297 vst1_u16(data, v);
298 printf("%s: (0x%x, 0x%x, 0x%x, 0x%x)\n", name, data[0], data[1], data[2], data[3]);
299}
300
301PX_FORCE_INLINE void printVec(const uint32x2_t& v, const char* name)
302{
303 PX_ALIGN(16, uint32_t) data[2];
304 vst1_u32(data, v);
305 printf("%s: (0x%x, 0x%x)\n", name, data[0], data[1]);
306}
307
308PX_FORCE_INLINE void printVar(const PxU32 v, const char* name)
309{
310 printf("%s: 0x%x\n", name, v);
311}
312
313PX_FORCE_INLINE void printVar(const PxF32 v, const char* name)
314{
315 printf("%s: %f\n", name, v);
316}
317
318#define PRINT_VAR(X) printVar((X), #X)
319#define PRINT_VEC(X) printVec((X), #X)
320#define PRINT_VEC_TITLE(TITLE, X) printVec((X), TITLE #X)
321#endif // debugging printf
322
326
327PX_FORCE_INLINE bool isFiniteFloatV(const FloatV a)
328{
329 PX_ALIGN(16, PxF32) data[4];
330 vst1_f32(reinterpret_cast<float32_t*>(data), a);
331 return PxIsFinite(data[0]) && PxIsFinite(data[1]);
332}
333
334PX_FORCE_INLINE bool isFiniteVec3V(const Vec3V a)
335{
336 PX_ALIGN(16, PxF32) data[4];
337 vst1q_f32(reinterpret_cast<float32_t*>(data), a);
338 return PxIsFinite(data[0]) && PxIsFinite(data[1]) && PxIsFinite(data[2]);
339}
340
341PX_FORCE_INLINE bool isFiniteVec4V(const Vec4V a)
342{
343 PX_ALIGN(16, PxF32) data[4];
344 vst1q_f32(reinterpret_cast<float32_t*>(data), a);
345 return PxIsFinite(data[0]) && PxIsFinite(data[1]) && PxIsFinite(data[2]) && PxIsFinite(data[3]);
346}
347
348PX_FORCE_INLINE bool hasZeroElementinFloatV(const FloatV a)
349{
350 ASSERT_ISVALIDFLOATV(a);
351 return vget_lane_u32(vreinterpret_u32_f32(a), 0) == 0;
352}
353
354PX_FORCE_INLINE bool hasZeroElementInVec3V(const Vec3V a)
355{
356 const uint32x2_t dLow = vget_low_u32(vreinterpretq_u32_f32(a));
357 const uint32x2_t dMin = vpmin_u32(dLow, dLow);
358
359 return vget_lane_u32(dMin, 0) == 0 || vgetq_lane_u32(vreinterpretq_u32_f32(a), 2) == 0;
360}
361
362PX_FORCE_INLINE bool hasZeroElementInVec4V(const Vec4V a)
363{
364 const uint32x2_t dHigh = vget_high_u32(vreinterpretq_u32_f32(a));
365 const uint32x2_t dLow = vget_low_u32(vreinterpretq_u32_f32(a));
366
367 const uint32x2_t dMin = vmin_u32(dHigh, dLow);
368 const uint32x2_t pairMin = vpmin_u32(dMin, dMin);
369 return vget_lane_u32(pairMin, 0) == 0;
370}
371
375
376PX_FORCE_INLINE FloatV FLoad(const PxF32 f)
377{
378 return vdup_n_f32(reinterpret_cast<const float32_t&>(f));
379}
380
381PX_FORCE_INLINE FloatV FLoadA(const PxF32* const f)
382{
383 ASSERT_ISALIGNED16(f);
384 return vld1_f32(reinterpret_cast<const float32_t*>(f));
385}
386
387PX_FORCE_INLINE Vec3V V3Load(const PxF32 f)
388{
389 PX_ALIGN(16, PxF32) data[4] = { f, f, f, 0.0f };
390 return V4LoadA(data);
391}
392
393PX_FORCE_INLINE Vec4V V4Load(const PxF32 f)
394{
395 return vdupq_n_f32(reinterpret_cast<const float32_t&>(f));
396}
397
398PX_FORCE_INLINE BoolV BLoad(const bool f)
399{
400 const PxU32 i = static_cast<PxU32>(-(static_cast<PxI32>(f)));
401 return vdupq_n_u32(i);
402}
403
404PX_FORCE_INLINE Vec3V V3LoadA(const PxVec3& f)
405{
406 ASSERT_ISALIGNED16(&f);
407 PX_ALIGN(16, PxF32) data[4] = { f.x, f.y, f.z, 0.0f };
408 return V4LoadA(data);
409}
410
411PX_FORCE_INLINE Vec3V V3LoadU(const PxVec3& f)
412{
413 PX_ALIGN(16, PxF32) data[4] = { f.x, f.y, f.z, 0.0f };
414 return V4LoadA(data);
415}
416
417PX_FORCE_INLINE Vec3V V3LoadUnsafeA(const PxVec3& f)
418{
419 ASSERT_ISALIGNED16(&f);
420 PX_ALIGN(16, PxF32) data[4] = { f.x, f.y, f.z, 0.0f };
421 return V4LoadA(data);
422}
423
424PX_FORCE_INLINE Vec3V V3LoadA(const PxF32* f)
425{
426 ASSERT_ISALIGNED16(f);
427 PX_ALIGN(16, PxF32) data[4] = { f[0], f[1], f[2], 0.0f };
428 return V4LoadA(data);
429}
430
431PX_FORCE_INLINE Vec3V V3LoadU(const PxF32* f)
432{
433 PX_ALIGN(16, PxF32) data[4] = { f[0], f[1], f[2], 0.0f };
434 return V4LoadA(data);
435}
436
437PX_FORCE_INLINE Vec3V Vec3V_From_Vec4V(Vec4V v)
438{
439 return vsetq_lane_f32(0.0f, v, 3);
440}
441
442PX_FORCE_INLINE Vec3V Vec3V_From_Vec4V_WUndefined(Vec4V v)
443{
444 return v;
445}
446
447PX_FORCE_INLINE Vec4V Vec4V_From_Vec3V(Vec3V f)
448{
449 return f; // ok if it is implemented as the same type.
450}
451
452PX_FORCE_INLINE Vec4V Vec4V_From_FloatV(FloatV f)
453{
454 return vcombine_f32(f, f);
455}
456
457PX_FORCE_INLINE Vec3V Vec3V_From_FloatV(FloatV f)
458{
459 return Vec3V_From_Vec4V(Vec4V_From_FloatV(f));
460}
461
462PX_FORCE_INLINE Vec3V Vec3V_From_FloatV_WUndefined(FloatV f)
463{
464 return Vec3V_From_Vec4V_WUndefined(Vec4V_From_FloatV(f));
465}
466
467PX_FORCE_INLINE Vec4V Vec4V_From_PxVec3_WUndefined(const PxVec3& f)
468{
469 PX_ALIGN(16, PxF32) data[4] = { f.x, f.y, f.z, 0.0f };
470 return V4LoadA(data);
471}
472
473PX_FORCE_INLINE Mat33V Mat33V_From_PxMat33(const PxMat33& m)
474{
475 return Mat33V(V3LoadU(m.column0), V3LoadU(m.column1), V3LoadU(m.column2));
476}
477
478PX_FORCE_INLINE void PxMat33_From_Mat33V(const Mat33V& m, PxMat33& out)
479{
480 V3StoreU(m.col0, out.column0);
481 V3StoreU(m.col1, out.column1);
482 V3StoreU(m.col2, out.column2);
483}
484
485PX_FORCE_INLINE Vec4V V4LoadA(const PxF32* const f)
486{
487 ASSERT_ISALIGNED16(f);
488 return vld1q_f32(reinterpret_cast<const float32_t*>(f));
489}
490
491PX_FORCE_INLINE void V4StoreA(Vec4V a, PxF32* f)
492{
493 ASSERT_ISALIGNED16(f);
494 vst1q_f32(reinterpret_cast<float32_t*>(f), a);
495}
496
497PX_FORCE_INLINE void V4StoreU(const Vec4V a, PxF32* f)
498{
499 PX_ALIGN(16, PxF32) f2[4];
500 vst1q_f32(reinterpret_cast<float32_t*>(f2), a);
501 f[0] = f2[0];
502 f[1] = f2[1];
503 f[2] = f2[2];
504 f[3] = f2[3];
505}
506
507PX_FORCE_INLINE void BStoreA(const BoolV a, PxU32* u)
508{
509 ASSERT_ISALIGNED16(u);
510 vst1q_u32(reinterpret_cast<uint32_t*>(u), a);
511}
512
513PX_FORCE_INLINE void U4StoreA(const VecU32V uv, PxU32* u)
514{
515 ASSERT_ISALIGNED16(u);
516 vst1q_u32(reinterpret_cast<uint32_t*>(u), uv);
517}
518
519PX_FORCE_INLINE void I4StoreA(const VecI32V iv, PxI32* i)
520{
521 ASSERT_ISALIGNED16(i);
522 vst1q_s32(reinterpret_cast<int32_t*>(i), iv);
523}
524
525PX_FORCE_INLINE Vec4V V4LoadU(const PxF32* const f)
526{
527 return vld1q_f32(reinterpret_cast<const float32_t*>(f));
528}
529
530PX_FORCE_INLINE BoolV BLoad(const bool* const f)
531{
532 const PX_ALIGN(16, PxU32) b[4] = { static_cast<PxU32>(-static_cast<PxI32>(f[0])),
533 static_cast<PxU32>(-static_cast<PxI32>(f[1])),
534 static_cast<PxU32>(-static_cast<PxI32>(f[2])),
535 static_cast<PxU32>(-static_cast<PxI32>(f[3])) };
536 return vld1q_u32(b);
537}
538
539PX_FORCE_INLINE void FStore(const FloatV a, PxF32* PX_RESTRICT f)
540{
541 ASSERT_ISVALIDFLOATV(a);
542 // vst1q_lane_f32(f, a, 0); // causes vst1 alignment bug
543 *f = vget_lane_f32(a, 0);
544}
545
546PX_FORCE_INLINE void Store_From_BoolV(const BoolV a, PxU32* PX_RESTRICT f)
547{
548 *f = vget_lane_u32(vget_low_u32(a), 0);
549}
550
551PX_FORCE_INLINE void V3StoreA(const Vec3V a, PxVec3& f)
552{
553 ASSERT_ISALIGNED16(&f);
554 PX_ALIGN(16, PxF32) f2[4];
555 vst1q_f32(reinterpret_cast<float32_t*>(f2), a);
556 f = PxVec3(f2[0], f2[1], f2[2]);
557}
558
559PX_FORCE_INLINE void V3StoreU(const Vec3V a, PxVec3& f)
560{
561 PX_ALIGN(16, PxF32) f2[4];
562 vst1q_f32(reinterpret_cast<float32_t*>(f2), a);
563 f = PxVec3(f2[0], f2[1], f2[2]);
564}
565
567// FLOATV
569
570PX_FORCE_INLINE FloatV FZero()
571{
572 return FLoad(0.0f);
573}
574
575PX_FORCE_INLINE FloatV FOne()
576{
577 return FLoad(1.0f);
578}
579
580PX_FORCE_INLINE FloatV FHalf()
581{
582 return FLoad(0.5f);
583}
584
585PX_FORCE_INLINE FloatV FEps()
586{
587 return FLoad(PX_EPS_REAL);
588}
589
590PX_FORCE_INLINE FloatV FEps6()
591{
592 return FLoad(1e-6f);
593}
594
595PX_FORCE_INLINE FloatV FMax()
596{
597 return FLoad(PX_MAX_REAL);
598}
599
600PX_FORCE_INLINE FloatV FNegMax()
601{
602 return FLoad(-PX_MAX_REAL);
603}
604
605PX_FORCE_INLINE FloatV IZero()
606{
607 return vreinterpret_f32_u32(vdup_n_u32(0));
608}
609
610PX_FORCE_INLINE FloatV IOne()
611{
612 return vreinterpret_f32_u32(vdup_n_u32(1));
613}
614
615PX_FORCE_INLINE FloatV ITwo()
616{
617 return vreinterpret_f32_u32(vdup_n_u32(2));
618}
619
620PX_FORCE_INLINE FloatV IThree()
621{
622 return vreinterpret_f32_u32(vdup_n_u32(3));
623}
624
625PX_FORCE_INLINE FloatV IFour()
626{
627 return vreinterpret_f32_u32(vdup_n_u32(4));
628}
629
630PX_FORCE_INLINE FloatV FNeg(const FloatV f)
631{
632 ASSERT_ISVALIDFLOATV(f);
633 return vneg_f32(f);
634}
635
636PX_FORCE_INLINE FloatV FAdd(const FloatV a, const FloatV b)
637{
638 ASSERT_ISVALIDFLOATV(a);
639 ASSERT_ISVALIDFLOATV(b);
640 return vadd_f32(a, b);
641}
642
643PX_FORCE_INLINE FloatV FSub(const FloatV a, const FloatV b)
644{
645 ASSERT_ISVALIDFLOATV(a);
646 ASSERT_ISVALIDFLOATV(b);
647 return vsub_f32(a, b);
648}
649
650PX_FORCE_INLINE FloatV FMul(const FloatV a, const FloatV b)
651{
652 ASSERT_ISVALIDFLOATV(a);
653 ASSERT_ISVALIDFLOATV(b);
654 return vmul_f32(a, b);
655}
656
657template <int n>
658PX_FORCE_INLINE float32x2_t recip_newton(const float32x2_t& in)
659{
660 float32x2_t recip = vrecpe_f32(in);
661 for(int i = 0; i < n; ++i)
662 recip = vmul_f32(recip, vrecps_f32(in, recip));
663 return recip;
664}
665
666template <int n>
667PX_FORCE_INLINE float32x4_t recipq_newton(const float32x4_t& in)
668{
669 float32x4_t recip = vrecpeq_f32(in);
670 for(int i = 0; i < n; ++i)
671 recip = vmulq_f32(recip, vrecpsq_f32(recip, in));
672 return recip;
673}
674
675template <int n>
676PX_FORCE_INLINE float32x2_t rsqrt_newton(const float32x2_t& in)
677{
678 float32x2_t rsqrt = vrsqrte_f32(in);
679 for(int i = 0; i < n; ++i)
680 rsqrt = vmul_f32(rsqrt, vrsqrts_f32(vmul_f32(rsqrt, rsqrt), in));
681 return rsqrt;
682}
683
684template <int n>
685PX_FORCE_INLINE float32x4_t rsqrtq_newton(const float32x4_t& in)
686{
687 float32x4_t rsqrt = vrsqrteq_f32(in);
688 for(int i = 0; i < n; ++i)
689 rsqrt = vmulq_f32(rsqrt, vrsqrtsq_f32(vmulq_f32(rsqrt, rsqrt), in));
690 return rsqrt;
691}
692
693PX_FORCE_INLINE FloatV FDiv(const FloatV a, const FloatV b)
694{
695 ASSERT_ISVALIDFLOATV(a);
696 ASSERT_ISVALIDFLOATV(b);
697 return vmul_f32(a, VRECIP(b));
698}
699
700PX_FORCE_INLINE FloatV FDivFast(const FloatV a, const FloatV b)
701{
702 ASSERT_ISVALIDFLOATV(a);
703 ASSERT_ISVALIDFLOATV(b);
704 return vmul_f32(a, VRECIPE(b));
705}
706
707PX_FORCE_INLINE FloatV FRecip(const FloatV a)
708{
709 ASSERT_ISVALIDFLOATV(a);
710 return VRECIP(a);
711}
712
713PX_FORCE_INLINE FloatV FRecipFast(const FloatV a)
714{
715 ASSERT_ISVALIDFLOATV(a);
716 return VRECIPE(a);
717}
718
719PX_FORCE_INLINE FloatV FRsqrt(const FloatV a)
720{
721 ASSERT_ISVALIDFLOATV(a);
722 return VRECIPSQRT(a);
723}
724
725PX_FORCE_INLINE FloatV FSqrt(const FloatV a)
726{
727 ASSERT_ISVALIDFLOATV(a);
728 return FSel(FIsEq(a, FZero()), a, vmul_f32(a, VRECIPSQRT(a)));
729}
730
731PX_FORCE_INLINE FloatV FRsqrtFast(const FloatV a)
732{
733 ASSERT_ISVALIDFLOATV(a);
734 return VRECIPSQRTE(a);
735}
736
737PX_FORCE_INLINE FloatV FScaleAdd(const FloatV a, const FloatV b, const FloatV c)
738{
739 ASSERT_ISVALIDFLOATV(a);
740 ASSERT_ISVALIDFLOATV(b);
741 ASSERT_ISVALIDFLOATV(c);
742 return vmla_f32(c, a, b);
743}
744
745PX_FORCE_INLINE FloatV FNegScaleSub(const FloatV a, const FloatV b, const FloatV c)
746{
747 ASSERT_ISVALIDFLOATV(a);
748 ASSERT_ISVALIDFLOATV(b);
749 ASSERT_ISVALIDFLOATV(c);
750 return vmls_f32(c, a, b);
751}
752
753PX_FORCE_INLINE FloatV FAbs(const FloatV a)
754{
755 ASSERT_ISVALIDFLOATV(a);
756 return vabs_f32(a);
757}
758
759PX_FORCE_INLINE FloatV FSel(const BoolV c, const FloatV a, const FloatV b)
760{
761 PX_ASSERT( vecMathTests::allElementsEqualBoolV(c, BTTTT()) ||
762 vecMathTests::allElementsEqualBoolV(c, BFFFF()));
763 ASSERT_ISVALIDFLOATV(vbsl_f32(vget_low_u32(c), a, b));
764 return vbsl_f32(vget_low_u32(c), a, b);
765}
766
767PX_FORCE_INLINE BoolV FIsGrtr(const FloatV a, const FloatV b)
768{
769 ASSERT_ISVALIDFLOATV(a);
770 ASSERT_ISVALIDFLOATV(b);
771 return vdupq_lane_u32(vcgt_f32(a, b), 0);
772}
773
774PX_FORCE_INLINE BoolV FIsGrtrOrEq(const FloatV a, const FloatV b)
775{
776 ASSERT_ISVALIDFLOATV(a);
777 ASSERT_ISVALIDFLOATV(b);
778 return vdupq_lane_u32(vcge_f32(a, b), 0);
779}
780
781PX_FORCE_INLINE BoolV FIsEq(const FloatV a, const FloatV b)
782{
783 ASSERT_ISVALIDFLOATV(a);
784 ASSERT_ISVALIDFLOATV(b);
785 return vdupq_lane_u32(vceq_f32(a, b), 0);
786}
787
788PX_FORCE_INLINE FloatV FMax(const FloatV a, const FloatV b)
789{
790 //ASSERT_ISVALIDFLOATV(a);
791 //ASSERT_ISVALIDFLOATV(b);
792 return vmax_f32(a, b);
793}
794
795PX_FORCE_INLINE FloatV FMin(const FloatV a, const FloatV b)
796{
797 //ASSERT_ISVALIDFLOATV(a);
798 //ASSERT_ISVALIDFLOATV(b);
799 return vmin_f32(a, b);
800}
801
802PX_FORCE_INLINE FloatV FClamp(const FloatV a, const FloatV minV, const FloatV maxV)
803{
804 ASSERT_ISVALIDFLOATV(minV);
805 ASSERT_ISVALIDFLOATV(maxV);
806 return vmax_f32(vmin_f32(a, maxV), minV);
807}
808
809PX_FORCE_INLINE PxU32 FAllGrtr(const FloatV a, const FloatV b)
810{
811 ASSERT_ISVALIDFLOATV(a);
812 ASSERT_ISVALIDFLOATV(b);
813 return vget_lane_u32(vcgt_f32(a, b), 0);
814}
815
816PX_FORCE_INLINE PxU32 FAllGrtrOrEq(const FloatV a, const FloatV b)
817{
818 ASSERT_ISVALIDFLOATV(a);
819 ASSERT_ISVALIDFLOATV(b);
820 return vget_lane_u32(vcge_f32(a, b), 0);
821}
822
823PX_FORCE_INLINE PxU32 FAllEq(const FloatV a, const FloatV b)
824{
825 ASSERT_ISVALIDFLOATV(a);
826 ASSERT_ISVALIDFLOATV(b);
827 return vget_lane_u32(vceq_f32(a, b), 0);
828}
829
830PX_FORCE_INLINE FloatV FRound(const FloatV a)
831{
832 ASSERT_ISVALIDFLOATV(a);
833
834 // truncate(a + (0.5f - sign(a)))
835 const float32x2_t half = vdup_n_f32(0.5f);
836 const float32x2_t sign = vcvt_f32_u32((vshr_n_u32(vreinterpret_u32_f32(a), 31)));
837 const float32x2_t aPlusHalf = vadd_f32(a, half);
838 const float32x2_t aRound = vsub_f32(aPlusHalf, sign);
839 int32x2_t tmp = vcvt_s32_f32(aRound);
840 return vcvt_f32_s32(tmp);
841}
842
843PX_FORCE_INLINE FloatV FSin(const FloatV a)
844{
845 ASSERT_ISVALIDFLOATV(a);
846
847 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
848 const FloatV recipTwoPi = FLoadA(g_PXReciprocalTwoPi.f);
849 const FloatV twoPi = FLoadA(g_PXTwoPi.f);
850 const FloatV tmp = FMul(a, recipTwoPi);
851 const FloatV b = FRound(tmp);
852 const FloatV V1 = FNegScaleSub(twoPi, b, a);
853
854 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
855 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
856 const FloatV V2 = FMul(V1, V1);
857 const FloatV V3 = FMul(V2, V1);
858 const FloatV V5 = FMul(V3, V2);
859 const FloatV V7 = FMul(V5, V2);
860 const FloatV V9 = FMul(V7, V2);
861 const FloatV V11 = FMul(V9, V2);
862 const FloatV V13 = FMul(V11, V2);
863 const FloatV V15 = FMul(V13, V2);
864 const FloatV V17 = FMul(V15, V2);
865 const FloatV V19 = FMul(V17, V2);
866 const FloatV V21 = FMul(V19, V2);
867 const FloatV V23 = FMul(V21, V2);
868
869 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
870 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
871 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
872
873 const FloatV S1 = V4GetY(sinCoefficients0);
874 const FloatV S2 = V4GetZ(sinCoefficients0);
875 const FloatV S3 = V4GetW(sinCoefficients0);
876 const FloatV S4 = V4GetX(sinCoefficients1);
877 const FloatV S5 = V4GetY(sinCoefficients1);
878 const FloatV S6 = V4GetZ(sinCoefficients1);
879 const FloatV S7 = V4GetW(sinCoefficients1);
880 const FloatV S8 = V4GetX(sinCoefficients2);
881 const FloatV S9 = V4GetY(sinCoefficients2);
882 const FloatV S10 = V4GetZ(sinCoefficients2);
883 const FloatV S11 = V4GetW(sinCoefficients2);
884
885 FloatV Result;
886 Result = FScaleAdd(S1, V3, V1);
887 Result = FScaleAdd(S2, V5, Result);
888 Result = FScaleAdd(S3, V7, Result);
889 Result = FScaleAdd(S4, V9, Result);
890 Result = FScaleAdd(S5, V11, Result);
891 Result = FScaleAdd(S6, V13, Result);
892 Result = FScaleAdd(S7, V15, Result);
893 Result = FScaleAdd(S8, V17, Result);
894 Result = FScaleAdd(S9, V19, Result);
895 Result = FScaleAdd(S10, V21, Result);
896 Result = FScaleAdd(S11, V23, Result);
897
898 return Result;
899}
900
901PX_FORCE_INLINE FloatV FCos(const FloatV a)
902{
903 ASSERT_ISVALIDFLOATV(a);
904
905 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
906 const FloatV recipTwoPi = FLoadA(g_PXReciprocalTwoPi.f);
907 const FloatV twoPi = FLoadA(g_PXTwoPi.f);
908 const FloatV tmp = FMul(a, recipTwoPi);
909 const FloatV b = FRound(tmp);
910 const FloatV V1 = FNegScaleSub(twoPi, b, a);
911
912 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
913 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
914 const FloatV V2 = FMul(V1, V1);
915 const FloatV V4 = FMul(V2, V2);
916 const FloatV V6 = FMul(V4, V2);
917 const FloatV V8 = FMul(V4, V4);
918 const FloatV V10 = FMul(V6, V4);
919 const FloatV V12 = FMul(V6, V6);
920 const FloatV V14 = FMul(V8, V6);
921 const FloatV V16 = FMul(V8, V8);
922 const FloatV V18 = FMul(V10, V8);
923 const FloatV V20 = FMul(V10, V10);
924 const FloatV V22 = FMul(V12, V10);
925
926 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
927 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
928 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
929
930 const FloatV C1 = V4GetY(cosCoefficients0);
931 const FloatV C2 = V4GetZ(cosCoefficients0);
932 const FloatV C3 = V4GetW(cosCoefficients0);
933 const FloatV C4 = V4GetX(cosCoefficients1);
934 const FloatV C5 = V4GetY(cosCoefficients1);
935 const FloatV C6 = V4GetZ(cosCoefficients1);
936 const FloatV C7 = V4GetW(cosCoefficients1);
937 const FloatV C8 = V4GetX(cosCoefficients2);
938 const FloatV C9 = V4GetY(cosCoefficients2);
939 const FloatV C10 = V4GetZ(cosCoefficients2);
940 const FloatV C11 = V4GetW(cosCoefficients2);
941
942 FloatV Result;
943 Result = FScaleAdd(C1, V2, FOne());
944 Result = FScaleAdd(C2, V4, Result);
945 Result = FScaleAdd(C3, V6, Result);
946 Result = FScaleAdd(C4, V8, Result);
947 Result = FScaleAdd(C5, V10, Result);
948 Result = FScaleAdd(C6, V12, Result);
949 Result = FScaleAdd(C7, V14, Result);
950 Result = FScaleAdd(C8, V16, Result);
951 Result = FScaleAdd(C9, V18, Result);
952 Result = FScaleAdd(C10, V20, Result);
953 Result = FScaleAdd(C11, V22, Result);
954
955 return Result;
956}
957
958PX_FORCE_INLINE PxU32 FOutOfBounds(const FloatV a, const FloatV min, const FloatV max)
959{
960 ASSERT_ISVALIDFLOATV(a);
961 ASSERT_ISVALIDFLOATV(min);
962 ASSERT_ISVALIDFLOATV(max);
963
964 const BoolV c = BOr(FIsGrtr(a, max), FIsGrtr(min, a));
965 return PxU32(!BAllEqFFFF(c));
966}
967
968PX_FORCE_INLINE PxU32 FInBounds(const FloatV a, const FloatV min, const FloatV max)
969{
970 ASSERT_ISVALIDFLOATV(a);
971 ASSERT_ISVALIDFLOATV(min);
972 ASSERT_ISVALIDFLOATV(max);
973
974 const BoolV c = BAnd(FIsGrtrOrEq(a, min), FIsGrtrOrEq(max, a));
975 return PxU32(BAllEqTTTT(c));
976}
977
978PX_FORCE_INLINE PxU32 FOutOfBounds(const FloatV a, const FloatV bounds)
979{
980 ASSERT_ISVALIDFLOATV(a);
981 ASSERT_ISVALIDFLOATV(bounds);
982 const uint32x2_t greater = vcagt_f32(a, bounds);
983 return vget_lane_u32(greater, 0);
984}
985
986PX_FORCE_INLINE PxU32 FInBounds(const FloatV a, const FloatV bounds)
987{
988 ASSERT_ISVALIDFLOATV(a);
989 ASSERT_ISVALIDFLOATV(bounds);
990 const uint32x2_t geq = vcage_f32(bounds, a);
991 return vget_lane_u32(geq, 0);
992}
993
995// VEC3V
997
998PX_FORCE_INLINE Vec3V V3Splat(const FloatV f)
999{
1000 ASSERT_ISVALIDFLOATV(f);
1001
1002 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1003 const uint32x2_t uHigh = vreinterpret_u32_f32(f);
1004 const float32x2_t dHigh = vreinterpret_f32_u32(vand_u32(uHigh, mask));
1005
1006 return vcombine_f32(f, dHigh);
1007}
1008
1009PX_FORCE_INLINE Vec3V V3Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z)
1010{
1011 ASSERT_ISVALIDFLOATV(x);
1012 ASSERT_ISVALIDFLOATV(y);
1013 ASSERT_ISVALIDFLOATV(z);
1014
1015 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1016 const uint32x2_t dHigh = vand_u32(vreinterpret_u32_f32(z), mask);
1017 const uint32x2_t dLow = vext_u32(vreinterpret_u32_f32(x), vreinterpret_u32_f32(y), 1);
1018 return vreinterpretq_f32_u32(vcombine_u32(dLow, dHigh));
1019}
1020
1021PX_FORCE_INLINE Vec3V V3UnitX()
1022{
1023 const float32x4_t x = { 1.0f, 0.0f, 0.0f, 0.0f };
1024 return x;
1025}
1026
1027PX_FORCE_INLINE Vec3V V3UnitY()
1028{
1029 const float32x4_t y = { 0, 1.0f, 0, 0 };
1030 return y;
1031}
1032
1033PX_FORCE_INLINE Vec3V V3UnitZ()
1034{
1035 const float32x4_t z = { 0, 0, 1.0f, 0 };
1036 return z;
1037}
1038
1039PX_FORCE_INLINE FloatV V3GetX(const Vec3V f)
1040{
1041 ASSERT_ISVALIDVEC3V(f);
1042 const float32x2_t fLow = vget_low_f32(f);
1043 return vdup_lane_f32(fLow, 0);
1044}
1045
1046PX_FORCE_INLINE FloatV V3GetY(const Vec3V f)
1047{
1048 ASSERT_ISVALIDVEC3V(f);
1049 const float32x2_t fLow = vget_low_f32(f);
1050 return vdup_lane_f32(fLow, 1);
1051}
1052
1053PX_FORCE_INLINE FloatV V3GetZ(const Vec3V f)
1054{
1055 ASSERT_ISVALIDVEC3V(f);
1056 const float32x2_t fhigh = vget_high_f32(f);
1057 return vdup_lane_f32(fhigh, 0);
1058}
1059
1060PX_FORCE_INLINE Vec3V V3SetX(const Vec3V v, const FloatV f)
1061{
1062 ASSERT_ISVALIDVEC3V(v);
1063 ASSERT_ISVALIDFLOATV(f);
1064 return V4Sel(BFTTT(), v, vcombine_f32(f, f));
1065}
1066
1067PX_FORCE_INLINE Vec3V V3SetY(const Vec3V v, const FloatV f)
1068{
1069 ASSERT_ISVALIDVEC3V(v);
1070 ASSERT_ISVALIDFLOATV(f);
1071 return V4Sel(BTFTT(), v, vcombine_f32(f, f));
1072}
1073
1074PX_FORCE_INLINE Vec3V V3SetZ(const Vec3V v, const FloatV f)
1075{
1076 ASSERT_ISVALIDVEC3V(v);
1077 ASSERT_ISVALIDFLOATV(f);
1078 return V4Sel(BTTFT(), v, vcombine_f32(f, f));
1079}
1080
1081PX_FORCE_INLINE Vec3V V3ColX(const Vec3V a, const Vec3V b, const Vec3V c)
1082{
1083 ASSERT_ISVALIDVEC3V(a);
1084 ASSERT_ISVALIDVEC3V(b);
1085 ASSERT_ISVALIDVEC3V(c);
1086
1087 const float32x2_t aLow = vget_low_f32(a);
1088 const float32x2_t bLow = vget_low_f32(b);
1089 const float32x2_t cLow = vget_low_f32(c);
1090 const float32x2_t zero = vdup_n_f32(0.0f);
1091
1092 const float32x2x2_t zipL = vzip_f32(aLow, bLow);
1093 const float32x2x2_t zipH = vzip_f32(cLow, zero);
1094
1095 return vcombine_f32(zipL.val[0], zipH.val[0]);
1096}
1097
1098PX_FORCE_INLINE Vec3V V3ColY(const Vec3V a, const Vec3V b, const Vec3V c)
1099{
1100 ASSERT_ISVALIDVEC3V(a);
1101 ASSERT_ISVALIDVEC3V(b);
1102 ASSERT_ISVALIDVEC3V(c);
1103
1104 const float32x2_t aLow = vget_low_f32(a);
1105 const float32x2_t bLow = vget_low_f32(b);
1106 const float32x2_t cLow = vget_low_f32(c);
1107 const float32x2_t zero = vdup_n_f32(0.0f);
1108
1109 const float32x2x2_t zipL = vzip_f32(aLow, bLow);
1110 const float32x2x2_t zipH = vzip_f32(cLow, zero);
1111
1112 return vcombine_f32(zipL.val[1], zipH.val[1]);
1113}
1114
1115PX_FORCE_INLINE Vec3V V3ColZ(const Vec3V a, const Vec3V b, const Vec3V c)
1116{
1117 ASSERT_ISVALIDVEC3V(a);
1118 ASSERT_ISVALIDVEC3V(b);
1119 ASSERT_ISVALIDVEC3V(c);
1120
1121 const float32x2_t aHi = vget_high_f32(a);
1122 const float32x2_t bHi = vget_high_f32(b);
1123 const float32x2_t cHi = vget_high_f32(c);
1124
1125 const float32x2x2_t zipL = vzip_f32(aHi, bHi);
1126
1127 return vcombine_f32(zipL.val[0], cHi);
1128}
1129
1130PX_FORCE_INLINE Vec3V V3Zero()
1131{
1132 return vdupq_n_f32(0.0f);
1133}
1134
1135PX_FORCE_INLINE Vec3V V3Eps()
1136{
1137 return V3Load(PX_EPS_REAL);
1138}
1139
1140PX_FORCE_INLINE Vec3V V3One()
1141{
1142 return V3Load(1.0f);
1143}
1144
1145PX_FORCE_INLINE Vec3V V3Neg(const Vec3V f)
1146{
1147 ASSERT_ISVALIDVEC3V(f);
1148 const float32x4_t tmp = vnegq_f32(f);
1149 return vsetq_lane_f32(0.0f, tmp, 3);
1150}
1151
1152PX_FORCE_INLINE Vec3V V3Add(const Vec3V a, const Vec3V b)
1153{
1154 ASSERT_ISVALIDVEC3V(a);
1155 ASSERT_ISVALIDVEC3V(b);
1156 return vaddq_f32(a, b);
1157}
1158
1159PX_FORCE_INLINE Vec3V V3Add(const Vec3V a, const FloatV b)
1160{
1161 ASSERT_ISVALIDVEC3V(a);
1162 ASSERT_ISVALIDFLOATV(b);
1163 return vaddq_f32(a, Vec3V_From_FloatV(b));
1164}
1165
1166PX_FORCE_INLINE Vec3V V3Sub(const Vec3V a, const Vec3V b)
1167{
1168 ASSERT_ISVALIDVEC3V(a);
1169 ASSERT_ISVALIDVEC3V(b);
1170 return vsubq_f32(a, b);
1171}
1172
1173PX_FORCE_INLINE Vec3V V3Sub(const Vec3V a, const FloatV b)
1174{
1175 ASSERT_ISVALIDVEC3V(a);
1176 ASSERT_ISVALIDFLOATV(b);
1177 return vsubq_f32(a, Vec3V_From_FloatV(b));
1178}
1179
1180PX_FORCE_INLINE Vec3V V3Scale(const Vec3V a, const FloatV b)
1181{
1182 ASSERT_ISVALIDVEC3V(a);
1183 ASSERT_ISVALIDFLOATV(b);
1184 const float32x4_t tmp = vmulq_lane_f32(a, b, 0);
1185 return vsetq_lane_f32(0.0f, tmp, 3);
1186}
1187
1188PX_FORCE_INLINE Vec3V V3Mul(const Vec3V a, const Vec3V b)
1189{
1190 ASSERT_ISVALIDVEC3V(a);
1191 ASSERT_ISVALIDVEC3V(b);
1192 return vmulq_f32(a, b);
1193}
1194
1195PX_FORCE_INLINE Vec3V V3ScaleInv(const Vec3V a, const FloatV b)
1196{
1197 ASSERT_ISVALIDVEC3V(a);
1198 ASSERT_ISVALIDFLOATV(b);
1199 const float32x2_t invB = VRECIP(b);
1200 const float32x4_t tmp = vmulq_lane_f32(a, invB, 0);
1201 return vsetq_lane_f32(0.0f, tmp, 3);
1202}
1203
1204PX_FORCE_INLINE Vec3V V3Div(const Vec3V a, const Vec3V b)
1205{
1206 ASSERT_ISVALIDVEC3V(a);
1207 ASSERT_ISVALIDVEC3V(b);
1208 float32x4_t invB = VRECIPQ(b);
1209 invB = vsetq_lane_f32(0.0f, invB, 3);
1210 return vmulq_f32(a, invB);
1211}
1212
1213PX_FORCE_INLINE Vec3V V3ScaleInvFast(const Vec3V a, const FloatV b)
1214{
1215 ASSERT_ISVALIDVEC3V(a);
1216 ASSERT_ISVALIDFLOATV(b);
1217 const float32x2_t invB = VRECIPE(b);
1218 const float32x4_t tmp = vmulq_lane_f32(a, invB, 0);
1219 return vsetq_lane_f32(0.0f, tmp, 3);
1220}
1221
1222PX_FORCE_INLINE Vec3V V3DivFast(const Vec3V a, const Vec3V b)
1223{
1224 ASSERT_ISVALIDVEC3V(a);
1225 ASSERT_ISVALIDVEC3V(b);
1226 float32x4_t invB = VRECIPEQ(b);
1227 invB = vsetq_lane_f32(0.0f, invB, 3);
1228 return vmulq_f32(a, invB);
1229}
1230
1231PX_FORCE_INLINE Vec3V V3Recip(const Vec3V a)
1232{
1233 ASSERT_ISVALIDVEC3V(a);
1234 const float32x4_t recipA = VRECIPQ(a);
1235 return vsetq_lane_f32(0.0f, recipA, 3);
1236}
1237
1238PX_FORCE_INLINE Vec3V V3RecipFast(const Vec3V a)
1239{
1240 ASSERT_ISVALIDVEC3V(a);
1241 const float32x4_t recipA = VRECIPEQ(a);
1242 return vsetq_lane_f32(0.0f, recipA, 3);
1243}
1244
1245PX_FORCE_INLINE Vec3V V3Rsqrt(const Vec3V a)
1246{
1247 ASSERT_ISVALIDVEC3V(a);
1248 const float32x4_t rSqrA = VRECIPSQRTQ(a);
1249 return vsetq_lane_f32(0.0f, rSqrA, 3);
1250}
1251
1252PX_FORCE_INLINE Vec3V V3RsqrtFast(const Vec3V a)
1253{
1254 ASSERT_ISVALIDVEC3V(a);
1255 const float32x4_t rSqrA = VRECIPSQRTEQ(a);
1256 return vsetq_lane_f32(0.0f, rSqrA, 3);
1257}
1258
1259PX_FORCE_INLINE Vec3V V3ScaleAdd(const Vec3V a, const FloatV b, const Vec3V c)
1260{
1261 ASSERT_ISVALIDVEC3V(a);
1262 ASSERT_ISVALIDFLOATV(b);
1263 ASSERT_ISVALIDVEC3V(c);
1264
1265 float32x4_t tmp = vmlaq_lane_f32(c, a, b, 0);
1266 // using vsetq_lane_f32 resulted in failures,
1267 // probably related to a compiler bug on
1268 // ndk r9d-win32, gcc 4.8, cardhu/shield
1269
1270 // code with issue
1271 // return vsetq_lane_f32(0.0f, tmp, 3);
1272
1273 // workaround
1274 float32x2_t w_z = vget_high_f32(tmp);
1275 float32x2_t y_x = vget_low_f32(tmp);
1276 w_z = vset_lane_f32(0.0f, w_z, 1);
1277 return vcombine_f32(y_x, w_z);
1278}
1279
1280PX_FORCE_INLINE Vec3V V3NegScaleSub(const Vec3V a, const FloatV b, const Vec3V c)
1281{
1282 ASSERT_ISVALIDVEC3V(a);
1283 ASSERT_ISVALIDFLOATV(b);
1284 ASSERT_ISVALIDVEC3V(c);
1285
1286 float32x4_t tmp = vmlsq_lane_f32(c, a, b, 0);
1287 // using vsetq_lane_f32 resulted in failures,
1288 // probably related to a compiler bug on
1289 // ndk r9d-win32, gcc 4.8, cardhu/shield
1290
1291 // code with issue
1292 // return vsetq_lane_f32(0.0f, tmp, 3);
1293
1294 // workaround
1295 float32x2_t w_z = vget_high_f32(tmp);
1296 float32x2_t y_x = vget_low_f32(tmp);
1297 w_z = vset_lane_f32(0.0f, w_z, 1);
1298 return vcombine_f32(y_x, w_z);
1299}
1300
1301PX_FORCE_INLINE Vec3V V3MulAdd(const Vec3V a, const Vec3V b, const Vec3V c)
1302{
1303 ASSERT_ISVALIDVEC3V(a);
1304 ASSERT_ISVALIDVEC3V(b);
1305 ASSERT_ISVALIDVEC3V(c);
1306 return vmlaq_f32(c, a, b);
1307}
1308
1309PX_FORCE_INLINE Vec3V V3NegMulSub(const Vec3V a, const Vec3V b, const Vec3V c)
1310{
1311 ASSERT_ISVALIDVEC3V(a);
1312 ASSERT_ISVALIDVEC3V(b);
1313 ASSERT_ISVALIDVEC3V(c);
1314 return vmlsq_f32(c, a, b);
1315}
1316
1317PX_FORCE_INLINE Vec3V V3Abs(const Vec3V a)
1318{
1319 ASSERT_ISVALIDVEC3V(a);
1320 return vabsq_f32(a);
1321}
1322
1323PX_FORCE_INLINE FloatV V3Dot(const Vec3V a, const Vec3V b)
1324{
1325 ASSERT_ISVALIDVEC3V(a);
1326 ASSERT_ISVALIDVEC3V(b);
1327
1328 // const uint32x2_t mask = {0xffffFFFF, 0x0};
1329 const float32x4_t tmp = vmulq_f32(a, b);
1330
1331 const float32x2_t low = vget_low_f32(tmp);
1332 const float32x2_t high = vget_high_f32(tmp);
1333 // const float32x2_t high = vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(high_), mask));
1334
1335 const float32x2_t sumTmp = vpadd_f32(low, high); // = {0+z, x+y}
1336 const float32x2_t sum0ZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z, x+y+z}
1337
1338 return sum0ZYX;
1339}
1340
1341PX_FORCE_INLINE Vec3V V3Cross(const Vec3V a, const Vec3V b)
1342{
1343 ASSERT_ISVALIDVEC3V(a);
1344 ASSERT_ISVALIDVEC3V(b);
1345
1346 const uint32x2_t TF = { 0xffffFFFF, 0x0 };
1347 const float32x2_t ay_ax = vget_low_f32(a); // d2
1348 const float32x2_t aw_az = vget_high_f32(a); // d3
1349 const float32x2_t by_bx = vget_low_f32(b); // d4
1350 const float32x2_t bw_bz = vget_high_f32(b); // d5
1351 // Hi, Lo
1352 const float32x2_t bz_by = vext_f32(by_bx, bw_bz, 1); // bz, by
1353 const float32x2_t az_ay = vext_f32(ay_ax, aw_az, 1); // az, ay
1354
1355 const float32x2_t azbx = vmul_f32(aw_az, by_bx); // 0, az*bx
1356 const float32x2_t aybz_axby = vmul_f32(ay_ax, bz_by); // ay*bz, ax*by
1357
1358 const float32x2_t azbxSUBaxbz = vmls_f32(azbx, bw_bz, ay_ax); // 0, az*bx-ax*bz
1359 const float32x2_t aybzSUBazby_axbySUBaybx = vmls_f32(aybz_axby, by_bx, az_ay); // ay*bz-az*by, ax*by-ay*bx
1360
1361 const float32x2_t retLow = vext_f32(aybzSUBazby_axbySUBaybx, azbxSUBaxbz, 1); // az*bx-ax*bz, ay*bz-az*by
1362 const uint32x2_t retHigh = vand_u32(TF, vreinterpret_u32_f32(aybzSUBazby_axbySUBaybx)); // 0, ax*by-ay*bx
1363
1364 return vcombine_f32(retLow, vreinterpret_f32_u32(retHigh));
1365}
1366
1367PX_FORCE_INLINE VecCrossV V3PrepareCross(const Vec3V a)
1368{
1369 ASSERT_ISVALIDVEC3V(a);
1370 return a;
1371}
1372
1373PX_FORCE_INLINE FloatV V3Length(const Vec3V a)
1374{
1375 ASSERT_ISVALIDVEC3V(a);
1376
1377 // const uint32x2_t mask = {0xffffFFFF, 0x0};
1378
1379 const float32x4_t tmp = vmulq_f32(a, a);
1380 const float32x2_t low = vget_low_f32(tmp);
1381 const float32x2_t high = vget_high_f32(tmp);
1382 // const float32x2_t high = vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(high_), mask));
1383
1384 const float32x2_t sumTmp = vpadd_f32(low, high); // = {0+z, x+y}
1385 const float32x2_t sum0ZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z, x+y+z}
1386
1387 return FSqrt(sum0ZYX);
1388}
1389
1390PX_FORCE_INLINE FloatV V3LengthSq(const Vec3V a)
1391{
1392 ASSERT_ISVALIDVEC3V(a);
1393 return V3Dot(a, a);
1394}
1395
1396PX_FORCE_INLINE Vec3V V3Normalize(const Vec3V a)
1397{
1398 ASSERT_ISVALIDVEC3V(a);
1399 //PX_ASSERT(!FAllEq(V4LengthSq(a), FZero()));
1400 return V3ScaleInv(a, V3Length(a));
1401}
1402
1403PX_FORCE_INLINE Vec3V V3NormalizeFast(const Vec3V a)
1404{
1405 ASSERT_ISVALIDVEC3V(a);
1406 //PX_ASSERT(!FAllEq(V4LengthSq(a), FZero()));
1407 return V3Scale(a, VRECIPSQRTE(V3Dot(a, a)));
1408}
1409
1410PX_FORCE_INLINE Vec3V V3NormalizeSafe(const Vec3V a, const Vec3V unsafeReturnValue)
1411{
1412 ASSERT_ISVALIDVEC3V(a);
1413 const FloatV zero = vdup_n_f32(0.0f);
1414 const FloatV length = V3Length(a);
1415 const uint32x4_t isGreaterThanZero = FIsGrtr(length, zero);
1416 return V3Sel(isGreaterThanZero, V3ScaleInv(a, length), unsafeReturnValue);
1417}
1418
1419PX_FORCE_INLINE Vec3V V3Sel(const BoolV c, const Vec3V a, const Vec3V b)
1420{
1421 ASSERT_ISVALIDVEC3V( vbslq_f32(c, a, b));
1422 return vbslq_f32(c, a, b);
1423}
1424
1425PX_FORCE_INLINE BoolV V3IsGrtr(const Vec3V a, const Vec3V b)
1426{
1427 ASSERT_ISVALIDVEC3V(a);
1428 ASSERT_ISVALIDVEC3V(b);
1429 return vcgtq_f32(a, b);
1430}
1431
1432PX_FORCE_INLINE BoolV V3IsGrtrOrEq(const Vec3V a, const Vec3V b)
1433{
1434 ASSERT_ISVALIDVEC3V(a);
1435 ASSERT_ISVALIDVEC3V(b);
1436 return vcgeq_f32(a, b);
1437}
1438
1439PX_FORCE_INLINE BoolV V3IsEq(const Vec3V a, const Vec3V b)
1440{
1441 ASSERT_ISVALIDVEC3V(a);
1442 ASSERT_ISVALIDVEC3V(b);
1443 return vceqq_f32(a, b);
1444}
1445
1446PX_FORCE_INLINE Vec3V V3Max(const Vec3V a, const Vec3V b)
1447{
1448 ASSERT_ISVALIDVEC3V(a);
1449 ASSERT_ISVALIDVEC3V(b);
1450 return vmaxq_f32(a, b);
1451}
1452
1453PX_FORCE_INLINE Vec3V V3Min(const Vec3V a, const Vec3V b)
1454{
1455 ASSERT_ISVALIDVEC3V(a);
1456 ASSERT_ISVALIDVEC3V(b);
1457 return vminq_f32(a, b);
1458}
1459
1460PX_FORCE_INLINE FloatV V3ExtractMax(const Vec3V a)
1461{
1462 ASSERT_ISVALIDVEC3V(a);
1463
1464 const float32x2_t low = vget_low_f32(a);
1465 const float32x2_t high = vget_high_f32(a);
1466
1467 const float32x2_t zz = vdup_lane_f32(high, 0);
1468 const float32x2_t max0 = vpmax_f32(zz, low);
1469 const float32x2_t max1 = vpmax_f32(max0, max0);
1470
1471 return max1;
1472}
1473
1474PX_FORCE_INLINE FloatV V3ExtractMin(const Vec3V a)
1475{
1476 ASSERT_ISVALIDVEC3V(a);
1477
1478 const float32x2_t low = vget_low_f32(a);
1479 const float32x2_t high = vget_high_f32(a);
1480
1481 const float32x2_t zz = vdup_lane_f32(high, 0);
1482 const float32x2_t min0 = vpmin_f32(zz, low);
1483 const float32x2_t min1 = vpmin_f32(min0, min0);
1484
1485 return min1;
1486}
1487
1488// return (a >= 0.0f) ? 1.0f : -1.0f;
1489PX_FORCE_INLINE Vec3V V3Sign(const Vec3V a)
1490{
1491 ASSERT_ISVALIDVEC3V(a);
1492 const Vec3V zero = V3Zero();
1493 const Vec3V one = V3One();
1494 const Vec3V none = V3Neg(one);
1495 return V3Sel(V3IsGrtrOrEq(a, zero), one, none);
1496}
1497
1498PX_FORCE_INLINE Vec3V V3Clamp(const Vec3V a, const Vec3V minV, const Vec3V maxV)
1499{
1500 ASSERT_ISVALIDVEC3V(minV);
1501 ASSERT_ISVALIDVEC3V(maxV);
1502 return V3Max(V3Min(a, maxV), minV);
1503}
1504
1505PX_FORCE_INLINE PxU32 V3AllGrtr(const Vec3V a, const Vec3V b)
1506{
1507 ASSERT_ISVALIDVEC3V(a);
1508 ASSERT_ISVALIDVEC3V(b);
1509 return internalUnitNeonSimd::BAllTrue3_R(V4IsGrtr(a, b));
1510}
1511
1512PX_FORCE_INLINE PxU32 V3AllGrtrOrEq(const Vec3V a, const Vec3V b)
1513{
1514 ASSERT_ISVALIDVEC3V(a);
1515 ASSERT_ISVALIDVEC3V(b);
1516 return internalUnitNeonSimd::BAllTrue3_R(V4IsGrtrOrEq(a, b));
1517}
1518
1519PX_FORCE_INLINE PxU32 V3AllEq(const Vec3V a, const Vec3V b)
1520{
1521 ASSERT_ISVALIDVEC3V(a);
1522 ASSERT_ISVALIDVEC3V(b);
1523 return internalUnitNeonSimd::BAllTrue3_R(V4IsEq(a, b));
1524}
1525
1526PX_FORCE_INLINE Vec3V V3Round(const Vec3V a)
1527{
1528 ASSERT_ISVALIDVEC3V(a);
1529 // truncate(a + (0.5f - sign(a)))
1530 const Vec3V half = V3Load(0.5f);
1531 const float32x4_t sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(a), 31)));
1532 const Vec3V aPlusHalf = V3Add(a, half);
1533 const Vec3V aRound = V3Sub(aPlusHalf, sign);
1534 return vcvtq_f32_s32(vcvtq_s32_f32(aRound));
1535}
1536
1537PX_FORCE_INLINE Vec3V V3Sin(const Vec3V a)
1538{
1539 ASSERT_ISVALIDVEC3V(a);
1540
1541 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
1542 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
1543 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
1544 const Vec3V tmp = V4Mul(a, recipTwoPi);
1545 const Vec3V b = V3Round(tmp);
1546 const Vec3V V1 = V4NegMulSub(twoPi, b, a);
1547
1548 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
1549 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
1550 const Vec3V V2 = V3Mul(V1, V1);
1551 const Vec3V V3 = V3Mul(V2, V1);
1552 const Vec3V V5 = V3Mul(V3, V2);
1553 const Vec3V V7 = V3Mul(V5, V2);
1554 const Vec3V V9 = V3Mul(V7, V2);
1555 const Vec3V V11 = V3Mul(V9, V2);
1556 const Vec3V V13 = V3Mul(V11, V2);
1557 const Vec3V V15 = V3Mul(V13, V2);
1558 const Vec3V V17 = V3Mul(V15, V2);
1559 const Vec3V V19 = V3Mul(V17, V2);
1560 const Vec3V V21 = V3Mul(V19, V2);
1561 const Vec3V V23 = V3Mul(V21, V2);
1562
1563 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
1564 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
1565 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
1566
1567 const FloatV S1 = V4GetY(sinCoefficients0);
1568 const FloatV S2 = V4GetZ(sinCoefficients0);
1569 const FloatV S3 = V4GetW(sinCoefficients0);
1570 const FloatV S4 = V4GetX(sinCoefficients1);
1571 const FloatV S5 = V4GetY(sinCoefficients1);
1572 const FloatV S6 = V4GetZ(sinCoefficients1);
1573 const FloatV S7 = V4GetW(sinCoefficients1);
1574 const FloatV S8 = V4GetX(sinCoefficients2);
1575 const FloatV S9 = V4GetY(sinCoefficients2);
1576 const FloatV S10 = V4GetZ(sinCoefficients2);
1577 const FloatV S11 = V4GetW(sinCoefficients2);
1578
1579 Vec3V Result;
1580 Result = V4ScaleAdd(V3, S1, V1);
1581 Result = V4ScaleAdd(V5, S2, Result);
1582 Result = V4ScaleAdd(V7, S3, Result);
1583 Result = V4ScaleAdd(V9, S4, Result);
1584 Result = V4ScaleAdd(V11, S5, Result);
1585 Result = V4ScaleAdd(V13, S6, Result);
1586 Result = V4ScaleAdd(V15, S7, Result);
1587 Result = V4ScaleAdd(V17, S8, Result);
1588 Result = V4ScaleAdd(V19, S9, Result);
1589 Result = V4ScaleAdd(V21, S10, Result);
1590 Result = V4ScaleAdd(V23, S11, Result);
1591
1592 return Result;
1593}
1594
1595PX_FORCE_INLINE Vec3V V3Cos(const Vec3V a)
1596{
1597 ASSERT_ISVALIDVEC3V(a);
1598
1599 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
1600 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
1601 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
1602 const Vec3V tmp = V4Mul(a, recipTwoPi);
1603 const Vec3V b = V3Round(tmp);
1604 const Vec3V V1 = V4NegMulSub(twoPi, b, a);
1605
1606 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
1607 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
1608 const Vec3V V2 = V3Mul(V1, V1);
1609 const Vec3V V4 = V3Mul(V2, V2);
1610 const Vec3V V6 = V3Mul(V4, V2);
1611 const Vec3V V8 = V3Mul(V4, V4);
1612 const Vec3V V10 = V3Mul(V6, V4);
1613 const Vec3V V12 = V3Mul(V6, V6);
1614 const Vec3V V14 = V3Mul(V8, V6);
1615 const Vec3V V16 = V3Mul(V8, V8);
1616 const Vec3V V18 = V3Mul(V10, V8);
1617 const Vec3V V20 = V3Mul(V10, V10);
1618 const Vec3V V22 = V3Mul(V12, V10);
1619
1620 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
1621 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
1622 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
1623
1624 const FloatV C1 = V4GetY(cosCoefficients0);
1625 const FloatV C2 = V4GetZ(cosCoefficients0);
1626 const FloatV C3 = V4GetW(cosCoefficients0);
1627 const FloatV C4 = V4GetX(cosCoefficients1);
1628 const FloatV C5 = V4GetY(cosCoefficients1);
1629 const FloatV C6 = V4GetZ(cosCoefficients1);
1630 const FloatV C7 = V4GetW(cosCoefficients1);
1631 const FloatV C8 = V4GetX(cosCoefficients2);
1632 const FloatV C9 = V4GetY(cosCoefficients2);
1633 const FloatV C10 = V4GetZ(cosCoefficients2);
1634 const FloatV C11 = V4GetW(cosCoefficients2);
1635
1636 Vec3V Result;
1637 Result = V4ScaleAdd(V2, C1, V4One());
1638 Result = V4ScaleAdd(V4, C2, Result);
1639 Result = V4ScaleAdd(V6, C3, Result);
1640 Result = V4ScaleAdd(V8, C4, Result);
1641 Result = V4ScaleAdd(V10, C5, Result);
1642 Result = V4ScaleAdd(V12, C6, Result);
1643 Result = V4ScaleAdd(V14, C7, Result);
1644 Result = V4ScaleAdd(V16, C8, Result);
1645 Result = V4ScaleAdd(V18, C9, Result);
1646 Result = V4ScaleAdd(V20, C10, Result);
1647 Result = V4ScaleAdd(V22, C11, Result);
1648
1649 return V4ClearW(Result);
1650}
1651
1652PX_FORCE_INLINE Vec3V V3PermYZZ(const Vec3V a)
1653{
1654 ASSERT_ISVALIDVEC3V(a);
1655 const float32x2_t xy = vget_low_f32(a);
1656 const float32x2_t zw = vget_high_f32(a);
1657 const float32x2_t yz = vext_f32(xy, zw, 1);
1658 return vcombine_f32(yz, zw);
1659}
1660
1661PX_FORCE_INLINE Vec3V V3PermXYX(const Vec3V a)
1662{
1663 ASSERT_ISVALIDVEC3V(a);
1664
1665 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1666 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
1667 const uint32x2_t xw = vand_u32(xy, mask);
1668 return vreinterpretq_f32_u32(vcombine_u32(xy, xw));
1669}
1670
1671PX_FORCE_INLINE Vec3V V3PermYZX(const Vec3V a)
1672{
1673 ASSERT_ISVALIDVEC3V(a);
1674
1675 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1676 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
1677 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(a));
1678 const uint32x2_t yz = vext_u32(xy, zw, 1);
1679 const uint32x2_t xw = vand_u32(xy, mask);
1680 return vreinterpretq_f32_u32(vcombine_u32(yz, xw));
1681}
1682
1683PX_FORCE_INLINE Vec3V V3PermZXY(const Vec3V a)
1684{
1685 ASSERT_ISVALIDVEC3V(a);
1686
1687 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
1688 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(a));
1689 const uint32x2_t wz = vrev64_u32(zw);
1690
1691 const uint32x2_t zx = vext_u32(wz, xy, 1);
1692 const uint32x2_t yw = vext_u32(xy, wz, 1);
1693
1694 return vreinterpretq_f32_u32(vcombine_u32(zx, yw));
1695}
1696
1697PX_FORCE_INLINE Vec3V V3PermZZY(const Vec3V a)
1698{
1699 ASSERT_ISVALIDVEC3V(a);
1700
1701 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
1702 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(a));
1703
1704 const uint32x2_t wz = vrev64_u32(zw);
1705 const uint32x2_t yw = vext_u32(xy, wz, 1);
1706 const uint32x2_t zz = vdup_lane_u32(wz, 1);
1707
1708 return vreinterpretq_f32_u32(vcombine_u32(zz, yw));
1709}
1710
1711PX_FORCE_INLINE Vec3V V3PermYXX(const Vec3V a)
1712{
1713 ASSERT_ISVALIDVEC3V(a);
1714
1715 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1716 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
1717 const uint32x2_t yx = vrev64_u32(xy);
1718 const uint32x2_t xw = vand_u32(xy, mask);
1719 return vreinterpretq_f32_u32(vcombine_u32(yx, xw));
1720}
1721
1722PX_FORCE_INLINE Vec3V V3Perm_Zero_1Z_0Y(const Vec3V v0, const Vec3V v1)
1723{
1724 ASSERT_ISVALIDVEC3V(v0);
1725 ASSERT_ISVALIDVEC3V(v1);
1726
1727 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(v0));
1728 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(v1));
1729 const uint32x2_t wz = vrev64_u32(zw);
1730 const uint32x2_t yw = vext_u32(xy, wz, 1);
1731
1732 return vreinterpretq_f32_u32(vcombine_u32(wz, yw));
1733}
1734
1735PX_FORCE_INLINE Vec3V V3Perm_0Z_Zero_1X(const Vec3V v0, const Vec3V v1)
1736{
1737 ASSERT_ISVALIDVEC3V(v0);
1738 ASSERT_ISVALIDVEC3V(v1);
1739
1740 const uint32x2_t mask = { 0xffffFFFF, 0x0 };
1741 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(v0));
1742 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(v1));
1743 const uint32x2_t xw = vand_u32(xy, mask);
1744
1745 return vreinterpretq_f32_u32(vcombine_u32(zw, xw));
1746}
1747
1748PX_FORCE_INLINE Vec3V V3Perm_1Y_0X_Zero(const Vec3V v0, const Vec3V v1)
1749{
1750 ASSERT_ISVALIDVEC3V(v0);
1751 ASSERT_ISVALIDVEC3V(v1);
1752
1753 const uint32x2_t axy = vget_low_u32(vreinterpretq_u32_f32(v0));
1754 const uint32x2_t bxy = vget_low_u32(vreinterpretq_u32_f32(v1));
1755 const uint32x2_t byax = vext_u32(bxy, axy, 1);
1756 const uint32x2_t ww = vdup_n_u32(0);
1757
1758 return vreinterpretq_f32_u32(vcombine_u32(byax, ww));
1759}
1760
1761PX_FORCE_INLINE FloatV V3SumElems(const Vec3V a)
1762{
1763 ASSERT_ISVALIDVEC3V(a);
1764
1765 // const uint32x2_t mask = {0xffffFFFF, 0x0};
1766
1767 const float32x2_t low = vget_low_f32(a);
1768 const float32x2_t high = vget_high_f32(a);
1769 // const float32x2_t high = vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(high_), mask));
1770
1771 const float32x2_t sumTmp = vpadd_f32(low, high); // = {0+z, x+y}
1772 const float32x2_t sum0ZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z, x+y+z}
1773
1774 return sum0ZYX;
1775}
1776
1777PX_FORCE_INLINE PxU32 V3OutOfBounds(const Vec3V a, const Vec3V min, const Vec3V max)
1778{
1779 ASSERT_ISVALIDVEC3V(a);
1780 ASSERT_ISVALIDVEC3V(min);
1781 ASSERT_ISVALIDVEC3V(max);
1782
1783 const BoolV c = BOr(V3IsGrtr(a, max), V3IsGrtr(min, a));
1784 return internalUnitNeonSimd::BAnyTrue3_R(c);
1785}
1786
1787PX_FORCE_INLINE PxU32 V3InBounds(const Vec3V a, const Vec3V min, const Vec3V max)
1788{
1789 ASSERT_ISVALIDVEC3V(a);
1790 ASSERT_ISVALIDVEC3V(min);
1791 ASSERT_ISVALIDVEC3V(max);
1792
1793 const BoolV c = BAnd(V3IsGrtrOrEq(a, min), V3IsGrtrOrEq(max, a));
1794 return internalUnitNeonSimd::BAllTrue4_R(c);
1795}
1796
1797PX_FORCE_INLINE PxU32 V3OutOfBounds(const Vec3V a, const Vec3V bounds)
1798{
1799 ASSERT_ISVALIDVEC3V(a);
1800 ASSERT_ISVALIDVEC3V(bounds);
1801
1802 const BoolV greater = V3IsGrtr(V3Abs(a), bounds);
1803 return internalUnitNeonSimd::BAnyTrue3_R(greater);
1804}
1805
1806PX_FORCE_INLINE PxU32 V3InBounds(const Vec3V a, const Vec3V bounds)
1807{
1808 ASSERT_ISVALIDVEC3V(a);
1809 ASSERT_ISVALIDVEC3V(bounds);
1810
1811 const BoolV greaterOrEq = V3IsGrtrOrEq(bounds, V3Abs(a));
1812 return internalUnitNeonSimd::BAllTrue4_R(greaterOrEq);
1813}
1814
1815PX_FORCE_INLINE void V3Transpose(Vec3V& col0, Vec3V& col1, Vec3V& col2)
1816{
1817 ASSERT_ISVALIDVEC3V(col0);
1818 ASSERT_ISVALIDVEC3V(col1);
1819 ASSERT_ISVALIDVEC3V(col2);
1820
1821 Vec3V col3 = V3Zero();
1822 const float32x4x2_t v0v1 = vzipq_f32(col0, col2);
1823 const float32x4x2_t v2v3 = vzipq_f32(col1, col3);
1824 const float32x4x2_t zip0 = vzipq_f32(v0v1.val[0], v2v3.val[0]);
1825 const float32x4x2_t zip1 = vzipq_f32(v0v1.val[1], v2v3.val[1]);
1826 col0 = zip0.val[0];
1827 col1 = zip0.val[1];
1828 col2 = zip1.val[0];
1829 // col3 = zip1.val[1];
1830}
1831
1833// VEC4V
1835
1836PX_FORCE_INLINE Vec4V V4Splat(const FloatV f)
1837{
1838 ASSERT_ISVALIDFLOATV(f);
1839 return vcombine_f32(f, f);
1840}
1841
1842PX_FORCE_INLINE Vec4V V4Merge(const FloatV* const floatVArray)
1843{
1844 ASSERT_ISVALIDFLOATV(floatVArray[0]);
1845 ASSERT_ISVALIDFLOATV(floatVArray[1]);
1846 ASSERT_ISVALIDFLOATV(floatVArray[2]);
1847 ASSERT_ISVALIDFLOATV(floatVArray[3]);
1848
1849 const uint32x2_t xLow = vreinterpret_u32_f32(floatVArray[0]);
1850 const uint32x2_t yLow = vreinterpret_u32_f32(floatVArray[1]);
1851 const uint32x2_t zLow = vreinterpret_u32_f32(floatVArray[2]);
1852 const uint32x2_t wLow = vreinterpret_u32_f32(floatVArray[3]);
1853
1854 const uint32x2_t dLow = vext_u32(xLow, yLow, 1);
1855 const uint32x2_t dHigh = vext_u32(zLow, wLow, 1);
1856
1857 return vreinterpretq_f32_u32(vcombine_u32(dLow, dHigh));
1858}
1859
1860PX_FORCE_INLINE Vec4V V4Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z, const FloatVArg w)
1861{
1862 ASSERT_ISVALIDFLOATV(x);
1863 ASSERT_ISVALIDFLOATV(y);
1864 ASSERT_ISVALIDFLOATV(z);
1865 ASSERT_ISVALIDFLOATV(w);
1866
1867 const uint32x2_t xLow = vreinterpret_u32_f32(x);
1868 const uint32x2_t yLow = vreinterpret_u32_f32(y);
1869 const uint32x2_t zLow = vreinterpret_u32_f32(z);
1870 const uint32x2_t wLow = vreinterpret_u32_f32(w);
1871
1872 const uint32x2_t dLow = vext_u32(xLow, yLow, 1);
1873 const uint32x2_t dHigh = vext_u32(zLow, wLow, 1);
1874
1875 return vreinterpretq_f32_u32(vcombine_u32(dLow, dHigh));
1876}
1877
1878PX_FORCE_INLINE Vec4V V4MergeW(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1879{
1880 const float32x2_t xx = vget_high_f32(x);
1881 const float32x2_t yy = vget_high_f32(y);
1882 const float32x2_t zz = vget_high_f32(z);
1883 const float32x2_t ww = vget_high_f32(w);
1884
1885 const float32x2x2_t zipL = vzip_f32(xx, yy);
1886 const float32x2x2_t zipH = vzip_f32(zz, ww);
1887
1888 return vcombine_f32(zipL.val[1], zipH.val[1]);
1889}
1890
1891PX_FORCE_INLINE Vec4V V4MergeZ(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1892{
1893 const float32x2_t xx = vget_high_f32(x);
1894 const float32x2_t yy = vget_high_f32(y);
1895 const float32x2_t zz = vget_high_f32(z);
1896 const float32x2_t ww = vget_high_f32(w);
1897
1898 const float32x2x2_t zipL = vzip_f32(xx, yy);
1899 const float32x2x2_t zipH = vzip_f32(zz, ww);
1900
1901 return vcombine_f32(zipL.val[0], zipH.val[0]);
1902}
1903
1904PX_FORCE_INLINE Vec4V V4MergeY(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1905{
1906 const float32x2_t xx = vget_low_f32(x);
1907 const float32x2_t yy = vget_low_f32(y);
1908 const float32x2_t zz = vget_low_f32(z);
1909 const float32x2_t ww = vget_low_f32(w);
1910
1911 const float32x2x2_t zipL = vzip_f32(xx, yy);
1912 const float32x2x2_t zipH = vzip_f32(zz, ww);
1913
1914 return vcombine_f32(zipL.val[1], zipH.val[1]);
1915}
1916
1917PX_FORCE_INLINE Vec4V V4MergeX(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1918{
1919 const float32x2_t xx = vget_low_f32(x);
1920 const float32x2_t yy = vget_low_f32(y);
1921 const float32x2_t zz = vget_low_f32(z);
1922 const float32x2_t ww = vget_low_f32(w);
1923
1924 const float32x2x2_t zipL = vzip_f32(xx, yy);
1925 const float32x2x2_t zipH = vzip_f32(zz, ww);
1926
1927 return vcombine_f32(zipL.val[0], zipH.val[0]);
1928}
1929
1930PX_FORCE_INLINE Vec4V V4UnpackXY(const Vec4VArg a, const Vec4VArg b)
1931{
1932 return vzipq_f32(a, b).val[0];
1933}
1934
1935PX_FORCE_INLINE Vec4V V4UnpackZW(const Vec4VArg a, const Vec4VArg b)
1936{
1937 return vzipq_f32(a, b).val[1];
1938}
1939
1940PX_FORCE_INLINE Vec4V V4UnitW()
1941{
1942 const float32x2_t zeros = vreinterpret_f32_u32(vmov_n_u32(0));
1943 const float32x2_t ones = vmov_n_f32(1.0f);
1944 const float32x2_t zo = vext_f32(zeros, ones, 1);
1945 return vcombine_f32(zeros, zo);
1946}
1947
1948PX_FORCE_INLINE Vec4V V4UnitX()
1949{
1950 const float32x2_t zeros = vreinterpret_f32_u32(vmov_n_u32(0));
1951 const float32x2_t ones = vmov_n_f32(1.0f);
1952 const float32x2_t oz = vext_f32(ones, zeros, 1);
1953 return vcombine_f32(oz, zeros);
1954}
1955
1956PX_FORCE_INLINE Vec4V V4UnitY()
1957{
1958 const float32x2_t zeros = vreinterpret_f32_u32(vmov_n_u32(0));
1959 const float32x2_t ones = vmov_n_f32(1.0f);
1960 const float32x2_t zo = vext_f32(zeros, ones, 1);
1961 return vcombine_f32(zo, zeros);
1962}
1963
1964PX_FORCE_INLINE Vec4V V4UnitZ()
1965{
1966 const float32x2_t zeros = vreinterpret_f32_u32(vmov_n_u32(0));
1967 const float32x2_t ones = vmov_n_f32(1.0f);
1968 const float32x2_t oz = vext_f32(ones, zeros, 1);
1969 return vcombine_f32(zeros, oz);
1970}
1971
1972PX_FORCE_INLINE FloatV V4GetW(const Vec4V f)
1973{
1974 const float32x2_t fhigh = vget_high_f32(f);
1975 return vdup_lane_f32(fhigh, 1);
1976}
1977
1978PX_FORCE_INLINE FloatV V4GetX(const Vec4V f)
1979{
1980 const float32x2_t fLow = vget_low_f32(f);
1981 return vdup_lane_f32(fLow, 0);
1982}
1983
1984PX_FORCE_INLINE FloatV V4GetY(const Vec4V f)
1985{
1986 const float32x2_t fLow = vget_low_f32(f);
1987 return vdup_lane_f32(fLow, 1);
1988}
1989
1990PX_FORCE_INLINE FloatV V4GetZ(const Vec4V f)
1991{
1992 const float32x2_t fhigh = vget_high_f32(f);
1993 return vdup_lane_f32(fhigh, 0);
1994}
1995
1996PX_FORCE_INLINE Vec4V V4SetW(const Vec4V v, const FloatV f)
1997{
1998 ASSERT_ISVALIDFLOATV(f);
1999 return V4Sel(BTTTF(), v, vcombine_f32(f, f));
2000}
2001
2002PX_FORCE_INLINE Vec4V V4SetX(const Vec4V v, const FloatV f)
2003{
2004 ASSERT_ISVALIDFLOATV(f);
2005 return V4Sel(BFTTT(), v, vcombine_f32(f, f));
2006}
2007
2008PX_FORCE_INLINE Vec4V V4SetY(const Vec4V v, const FloatV f)
2009{
2010 ASSERT_ISVALIDFLOATV(f);
2011 return V4Sel(BTFTT(), v, vcombine_f32(f, f));
2012}
2013
2014PX_FORCE_INLINE Vec4V V4SetZ(const Vec4V v, const FloatV f)
2015{
2016 ASSERT_ISVALIDFLOATV(f);
2017 return V4Sel(BTTFT(), v, vcombine_f32(f, f));
2018}
2019
2020PX_FORCE_INLINE Vec4V V4ClearW(const Vec4V v)
2021{
2022 return V4Sel(BTTTF(), v, V4Zero());
2023}
2024
2025PX_FORCE_INLINE Vec4V V4PermYXWZ(const Vec4V a)
2026{
2027 const float32x2_t xy = vget_low_f32(a);
2028 const float32x2_t zw = vget_high_f32(a);
2029 const float32x2_t yx = vext_f32(xy, xy, 1);
2030 const float32x2_t wz = vext_f32(zw, zw, 1);
2031 return vcombine_f32(yx, wz);
2032}
2033
2034PX_FORCE_INLINE Vec4V V4PermXZXZ(const Vec4V a)
2035{
2036 const float32x2_t xy = vget_low_f32(a);
2037 const float32x2_t zw = vget_high_f32(a);
2038 const float32x2x2_t xzyw = vzip_f32(xy, zw);
2039 return vcombine_f32(xzyw.val[0], xzyw.val[0]);
2040}
2041
2042PX_FORCE_INLINE Vec4V V4PermYWYW(const Vec4V a)
2043{
2044 const float32x2_t xy = vget_low_f32(a);
2045 const float32x2_t zw = vget_high_f32(a);
2046 const float32x2x2_t xzyw = vzip_f32(xy, zw);
2047 return vcombine_f32(xzyw.val[1], xzyw.val[1]);
2048}
2049
2050PX_FORCE_INLINE Vec4V V4PermYZXW(const Vec4V a)
2051{
2052 const uint32x2_t xy = vget_low_u32(vreinterpretq_u32_f32(a));
2053 const uint32x2_t zw = vget_high_u32(vreinterpretq_u32_f32(a));
2054 const uint32x2_t yz = vext_u32(xy, zw, 1);
2055 const uint32x2_t xw = vrev64_u32(vext_u32(zw, xy, 1));
2056 return vreinterpretq_f32_u32(vcombine_u32(yz, xw));
2057}
2058
2059PX_FORCE_INLINE Vec4V V4PermZWXY(const Vec4V a)
2060{
2061 const float32x2_t low = vget_low_f32(a);
2062 const float32x2_t high = vget_high_f32(a);
2063 return vcombine_f32(high, low);
2064}
2065
2066template <PxU8 E0, PxU8 E1, PxU8 E2, PxU8 E3>
2067PX_FORCE_INLINE Vec4V V4Perm(const Vec4V V)
2068{
2069 static const uint32_t ControlElement[4] =
2070 {
2071#if 1
2072 0x03020100, // XM_SWIZZLE_X
2073 0x07060504, // XM_SWIZZLE_Y
2074 0x0B0A0908, // XM_SWIZZLE_Z
2075 0x0F0E0D0C, // XM_SWIZZLE_W
2076#else
2077 0x00010203, // XM_SWIZZLE_X
2078 0x04050607, // XM_SWIZZLE_Y
2079 0x08090A0B, // XM_SWIZZLE_Z
2080 0x0C0D0E0F, // XM_SWIZZLE_W
2081#endif
2082 };
2083
2084 uint8x8x2_t tbl;
2085 tbl.val[0] = vreinterpret_u8_f32(vget_low_f32(V));
2086 tbl.val[1] = vreinterpret_u8_f32(vget_high_f32(V));
2087
2088 uint8x8_t idx =
2089 vcreate_u8(static_cast<uint64_t>(ControlElement[E0]) | (static_cast<uint64_t>(ControlElement[E1]) << 32));
2090 const uint8x8_t rL = vtbl2_u8(tbl, idx);
2091 idx = vcreate_u8(static_cast<uint64_t>(ControlElement[E2]) | (static_cast<uint64_t>(ControlElement[E3]) << 32));
2092 const uint8x8_t rH = vtbl2_u8(tbl, idx);
2093 return vreinterpretq_f32_u8(vcombine_u8(rL, rH));
2094}
2095
2096// PT: this seems measurably slower than the hardcoded version
2097/*PX_FORCE_INLINE Vec4V V4PermYZXW(const Vec4V a)
2098{
2099 return V4Perm<1, 2, 0, 3>(a);
2100}*/
2101
2102PX_FORCE_INLINE Vec4V V4Zero()
2103{
2104 return vreinterpretq_f32_u32(vmovq_n_u32(0));
2105 // return vmovq_n_f32(0.0f);
2106}
2107
2108PX_FORCE_INLINE Vec4V V4One()
2109{
2110 return vmovq_n_f32(1.0f);
2111}
2112
2113PX_FORCE_INLINE Vec4V V4Eps()
2114{
2115 // return vmovq_n_f32(PX_EPS_REAL);
2116 return V4Load(PX_EPS_REAL);
2117}
2118
2119PX_FORCE_INLINE Vec4V V4Neg(const Vec4V f)
2120{
2121 return vnegq_f32(f);
2122}
2123
2124PX_FORCE_INLINE Vec4V V4Add(const Vec4V a, const Vec4V b)
2125{
2126 return vaddq_f32(a, b);
2127}
2128
2129PX_FORCE_INLINE Vec4V V4Sub(const Vec4V a, const Vec4V b)
2130{
2131 return vsubq_f32(a, b);
2132}
2133
2134PX_FORCE_INLINE Vec4V V4Scale(const Vec4V a, const FloatV b)
2135{
2136 return vmulq_lane_f32(a, b, 0);
2137}
2138
2139PX_FORCE_INLINE Vec4V V4Mul(const Vec4V a, const Vec4V b)
2140{
2141 return vmulq_f32(a, b);
2142}
2143
2144PX_FORCE_INLINE Vec4V V4ScaleInv(const Vec4V a, const FloatV b)
2145{
2146 ASSERT_ISVALIDFLOATV(b);
2147 const float32x2_t invB = VRECIP(b);
2148 return vmulq_lane_f32(a, invB, 0);
2149}
2150
2151PX_FORCE_INLINE Vec4V V4Div(const Vec4V a, const Vec4V b)
2152{
2153 const float32x4_t invB = VRECIPQ(b);
2154 return vmulq_f32(a, invB);
2155}
2156
2157PX_FORCE_INLINE Vec4V V4ScaleInvFast(const Vec4V a, const FloatV b)
2158{
2159 ASSERT_ISVALIDFLOATV(b);
2160 const float32x2_t invB = VRECIPE(b);
2161 return vmulq_lane_f32(a, invB, 0);
2162}
2163
2164PX_FORCE_INLINE Vec4V V4DivFast(const Vec4V a, const Vec4V b)
2165{
2166 const float32x4_t invB = VRECIPEQ(b);
2167 return vmulq_f32(a, invB);
2168}
2169
2170PX_FORCE_INLINE Vec4V V4Recip(const Vec4V a)
2171{
2172 return VRECIPQ(a);
2173}
2174
2175PX_FORCE_INLINE Vec4V V4RecipFast(const Vec4V a)
2176{
2177 return VRECIPEQ(a);
2178}
2179
2180PX_FORCE_INLINE Vec4V V4Rsqrt(const Vec4V a)
2181{
2182 return VRECIPSQRTQ(a);
2183}
2184
2185PX_FORCE_INLINE Vec4V V4RsqrtFast(const Vec4V a)
2186{
2187 return VRECIPSQRTEQ(a);
2188}
2189
2190PX_FORCE_INLINE Vec4V V4Sqrt(const Vec4V a)
2191{
2192 return V4Sel(V4IsEq(a, V4Zero()), a, V4Mul(a, VRECIPSQRTQ(a)));
2193}
2194
2195PX_FORCE_INLINE Vec4V V4ScaleAdd(const Vec4V a, const FloatV b, const Vec4V c)
2196{
2197 ASSERT_ISVALIDFLOATV(b);
2198 return vmlaq_lane_f32(c, a, b, 0);
2199}
2200
2201PX_FORCE_INLINE Vec4V V4NegScaleSub(const Vec4V a, const FloatV b, const Vec4V c)
2202{
2203 ASSERT_ISVALIDFLOATV(b);
2204 return vmlsq_lane_f32(c, a, b, 0);
2205}
2206
2207PX_FORCE_INLINE Vec4V V4MulAdd(const Vec4V a, const Vec4V b, const Vec4V c)
2208{
2209 return vmlaq_f32(c, a, b);
2210}
2211
2212PX_FORCE_INLINE Vec4V V4NegMulSub(const Vec4V a, const Vec4V b, const Vec4V c)
2213{
2214 return vmlsq_f32(c, a, b);
2215}
2216
2217PX_FORCE_INLINE Vec4V V4Abs(const Vec4V a)
2218{
2219 return vabsq_f32(a);
2220}
2221
2222PX_FORCE_INLINE FloatV V4SumElements(const Vec4V a)
2223{
2224 const Vec4V xy = V4UnpackXY(a, a); // x,x,y,y
2225 const Vec4V zw = V4UnpackZW(a, a); // z,z,w,w
2226 const Vec4V xz_yw = V4Add(xy, zw); // x+z,x+z,y+w,y+w
2227 const FloatV xz = V4GetX(xz_yw); // x+z
2228 const FloatV yw = V4GetZ(xz_yw); // y+w
2229 return FAdd(xz, yw); // sum
2230}
2231
2232PX_FORCE_INLINE FloatV V4Dot(const Vec4V a, const Vec4V b)
2233{
2234 const float32x4_t tmp = vmulq_f32(a, b);
2235 const float32x2_t low = vget_low_f32(tmp);
2236 const float32x2_t high = vget_high_f32(tmp);
2237
2238 const float32x2_t sumTmp = vpadd_f32(low, high); // = {z+w, x+y}
2239 const float32x2_t sumWZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z+w, x+y+z+w}
2240 return sumWZYX;
2241}
2242
2243PX_FORCE_INLINE FloatV V4Dot3(const Vec4V aa, const Vec4V bb)
2244{
2245 // PT: the V3Dot code relies on the fact that W=0 so we can't reuse it as-is, we need to clear W first.
2246 // TODO: find a better implementation that does not need to clear W.
2247 const Vec4V a = V4ClearW(aa);
2248 const Vec4V b = V4ClearW(bb);
2249
2250 const float32x4_t tmp = vmulq_f32(a, b);
2251 const float32x2_t low = vget_low_f32(tmp);
2252 const float32x2_t high = vget_high_f32(tmp);
2253
2254 const float32x2_t sumTmp = vpadd_f32(low, high); // = {0+z, x+y}
2255 const float32x2_t sum0ZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z, x+y+z}
2256 return sum0ZYX;
2257}
2258
2259PX_FORCE_INLINE Vec4V V4Cross(const Vec4V a, const Vec4V b)
2260{
2261 const uint32x2_t TF = { 0xffffFFFF, 0x0 };
2262 const float32x2_t ay_ax = vget_low_f32(a); // d2
2263 const float32x2_t aw_az = vget_high_f32(a); // d3
2264 const float32x2_t by_bx = vget_low_f32(b); // d4
2265 const float32x2_t bw_bz = vget_high_f32(b); // d5
2266 // Hi, Lo
2267 const float32x2_t bz_by = vext_f32(by_bx, bw_bz, 1); // bz, by
2268 const float32x2_t az_ay = vext_f32(ay_ax, aw_az, 1); // az, ay
2269
2270 const float32x2_t azbx = vmul_f32(aw_az, by_bx); // 0, az*bx
2271 const float32x2_t aybz_axby = vmul_f32(ay_ax, bz_by); // ay*bz, ax*by
2272
2273 const float32x2_t azbxSUBaxbz = vmls_f32(azbx, bw_bz, ay_ax); // 0, az*bx-ax*bz
2274 const float32x2_t aybzSUBazby_axbySUBaybx = vmls_f32(aybz_axby, by_bx, az_ay); // ay*bz-az*by, ax*by-ay*bx
2275
2276 const float32x2_t retLow = vext_f32(aybzSUBazby_axbySUBaybx, azbxSUBaxbz, 1); // az*bx-ax*bz, ay*bz-az*by
2277 const uint32x2_t retHigh = vand_u32(TF, vreinterpret_u32_f32(aybzSUBazby_axbySUBaybx)); // 0, ax*by-ay*bx
2278
2279 return vcombine_f32(retLow, vreinterpret_f32_u32(retHigh));
2280}
2281
2282PX_FORCE_INLINE FloatV V4Length(const Vec4V a)
2283{
2284 const float32x4_t tmp = vmulq_f32(a, a);
2285 const float32x2_t low = vget_low_f32(tmp);
2286 const float32x2_t high = vget_high_f32(tmp);
2287
2288 const float32x2_t sumTmp = vpadd_f32(low, high); // = {0+z, x+y}
2289 const float32x2_t sumWZYX = vpadd_f32(sumTmp, sumTmp); // = {x+y+z, x+y+z}
2290 return FSqrt(sumWZYX);
2291}
2292
2293PX_FORCE_INLINE FloatV V4LengthSq(const Vec4V a)
2294{
2295 return V4Dot(a, a);
2296}
2297
2298PX_FORCE_INLINE Vec4V V4Normalize(const Vec4V a)
2299{
2300 //PX_ASSERT(!FAllEq(V4LengthSq(a), FZero()));
2301 return V4ScaleInv(a, V4Length(a));
2302}
2303
2304PX_FORCE_INLINE Vec4V V4NormalizeFast(const Vec4V a)
2305{
2306 //PX_ASSERT(!FAllEq(V4LengthSq(a), FZero()));
2307 return V4Scale(a, FRsqrtFast(V4Dot(a, a)));
2308}
2309
2310PX_FORCE_INLINE Vec4V V4NormalizeSafe(const Vec4V a, const Vec4V unsafeReturnValue)
2311{
2312 const FloatV zero = FZero();
2313 const FloatV length = V4Length(a);
2314 const uint32x4_t isGreaterThanZero = FIsGrtr(length, zero);
2315 return V4Sel(isGreaterThanZero, V4ScaleInv(a, length), unsafeReturnValue);
2316}
2317
2318PX_FORCE_INLINE BoolV V4IsEqU32(const VecU32V a, const VecU32V b)
2319{
2320 return vceqq_u32(a, b);
2321}
2322
2323PX_FORCE_INLINE Vec4V V4Sel(const BoolV c, const Vec4V a, const Vec4V b)
2324{
2325 return vbslq_f32(c, a, b);
2326}
2327
2328PX_FORCE_INLINE BoolV V4IsGrtr(const Vec4V a, const Vec4V b)
2329{
2330 return vcgtq_f32(a, b);
2331}
2332
2333PX_FORCE_INLINE BoolV V4IsGrtrOrEq(const Vec4V a, const Vec4V b)
2334{
2335 return vcgeq_f32(a, b);
2336}
2337
2338PX_FORCE_INLINE BoolV V4IsEq(const Vec4V a, const Vec4V b)
2339{
2340 return vceqq_f32(a, b);
2341}
2342
2343PX_FORCE_INLINE Vec4V V4Max(const Vec4V a, const Vec4V b)
2344{
2345 return vmaxq_f32(a, b);
2346}
2347
2348PX_FORCE_INLINE Vec4V V4Min(const Vec4V a, const Vec4V b)
2349{
2350 return vminq_f32(a, b);
2351}
2352
2353PX_FORCE_INLINE FloatV V4ExtractMax(const Vec4V a)
2354{
2355 const float32x2_t low = vget_low_f32(a);
2356 const float32x2_t high = vget_high_f32(a);
2357
2358 const float32x2_t max0 = vpmax_f32(high, low);
2359 const float32x2_t max1 = vpmax_f32(max0, max0);
2360
2361 return max1;
2362}
2363
2364PX_FORCE_INLINE FloatV V4ExtractMin(const Vec4V a)
2365{
2366 const float32x2_t low = vget_low_f32(a);
2367 const float32x2_t high = vget_high_f32(a);
2368
2369 const float32x2_t min0 = vpmin_f32(high, low);
2370 const float32x2_t min1 = vpmin_f32(min0, min0);
2371
2372 return min1;
2373}
2374
2375PX_FORCE_INLINE Vec4V V4Clamp(const Vec4V a, const Vec4V minV, const Vec4V maxV)
2376{
2377 return V4Max(V4Min(a, maxV), minV);
2378}
2379
2380PX_FORCE_INLINE PxU32 V4AllGrtr(const Vec4V a, const Vec4V b)
2381{
2382 return internalUnitNeonSimd::BAllTrue4_R(V4IsGrtr(a, b));
2383}
2384
2385PX_FORCE_INLINE PxU32 V4AllGrtrOrEq(const Vec4V a, const Vec4V b)
2386{
2387 return internalUnitNeonSimd::BAllTrue4_R(V4IsGrtrOrEq(a, b));
2388}
2389
2390PX_FORCE_INLINE PxU32 V4AllGrtrOrEq3(const Vec4V a, const Vec4V b)
2391{
2392 return internalUnitNeonSimd::BAllTrue3_R(V4IsGrtrOrEq(a, b));
2393}
2394
2395PX_FORCE_INLINE PxU32 V4AllEq(const Vec4V a, const Vec4V b)
2396{
2397 return internalUnitNeonSimd::BAllTrue4_R(V4IsEq(a, b));
2398}
2399
2400PX_FORCE_INLINE PxU32 V4AnyGrtr3(const Vec4V a, const Vec4V b)
2401{
2402 return internalUnitNeonSimd::BAnyTrue3_R(V4IsGrtr(a, b));
2403}
2404
2405PX_FORCE_INLINE Vec4V V4Round(const Vec4V a)
2406{
2407 // truncate(a + (0.5f - sign(a)))
2408 const Vec4V half = V4Load(0.5f);
2409 const float32x4_t sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(a), 31)));
2410 const Vec4V aPlusHalf = V4Add(a, half);
2411 const Vec4V aRound = V4Sub(aPlusHalf, sign);
2412 return vcvtq_f32_s32(vcvtq_s32_f32(aRound));
2413}
2414
2415PX_FORCE_INLINE Vec4V V4Sin(const Vec4V a)
2416{
2417 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
2418 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
2419 const Vec4V tmp = V4Mul(a, recipTwoPi);
2420 const Vec4V b = V4Round(tmp);
2421 const Vec4V V1 = V4NegMulSub(twoPi, b, a);
2422
2423 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
2424 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
2425 const Vec4V V2 = V4Mul(V1, V1);
2426 const Vec4V V3 = V4Mul(V2, V1);
2427 const Vec4V V5 = V4Mul(V3, V2);
2428 const Vec4V V7 = V4Mul(V5, V2);
2429 const Vec4V V9 = V4Mul(V7, V2);
2430 const Vec4V V11 = V4Mul(V9, V2);
2431 const Vec4V V13 = V4Mul(V11, V2);
2432 const Vec4V V15 = V4Mul(V13, V2);
2433 const Vec4V V17 = V4Mul(V15, V2);
2434 const Vec4V V19 = V4Mul(V17, V2);
2435 const Vec4V V21 = V4Mul(V19, V2);
2436 const Vec4V V23 = V4Mul(V21, V2);
2437
2438 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
2439 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
2440 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
2441
2442 const FloatV S1 = V4GetY(sinCoefficients0);
2443 const FloatV S2 = V4GetZ(sinCoefficients0);
2444 const FloatV S3 = V4GetW(sinCoefficients0);
2445 const FloatV S4 = V4GetX(sinCoefficients1);
2446 const FloatV S5 = V4GetY(sinCoefficients1);
2447 const FloatV S6 = V4GetZ(sinCoefficients1);
2448 const FloatV S7 = V4GetW(sinCoefficients1);
2449 const FloatV S8 = V4GetX(sinCoefficients2);
2450 const FloatV S9 = V4GetY(sinCoefficients2);
2451 const FloatV S10 = V4GetZ(sinCoefficients2);
2452 const FloatV S11 = V4GetW(sinCoefficients2);
2453
2454 Vec4V Result;
2455 Result = V4ScaleAdd(V3, S1, V1);
2456 Result = V4ScaleAdd(V5, S2, Result);
2457 Result = V4ScaleAdd(V7, S3, Result);
2458 Result = V4ScaleAdd(V9, S4, Result);
2459 Result = V4ScaleAdd(V11, S5, Result);
2460 Result = V4ScaleAdd(V13, S6, Result);
2461 Result = V4ScaleAdd(V15, S7, Result);
2462 Result = V4ScaleAdd(V17, S8, Result);
2463 Result = V4ScaleAdd(V19, S9, Result);
2464 Result = V4ScaleAdd(V21, S10, Result);
2465 Result = V4ScaleAdd(V23, S11, Result);
2466
2467 return Result;
2468}
2469
2470PX_FORCE_INLINE Vec4V V4Cos(const Vec4V a)
2471{
2472 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
2473 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
2474 const Vec4V tmp = V4Mul(a, recipTwoPi);
2475 const Vec4V b = V4Round(tmp);
2476 const Vec4V V1 = V4NegMulSub(twoPi, b, a);
2477
2478 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
2479 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
2480 const Vec4V V2 = V4Mul(V1, V1);
2481 const Vec4V V4 = V4Mul(V2, V2);
2482 const Vec4V V6 = V4Mul(V4, V2);
2483 const Vec4V V8 = V4Mul(V4, V4);
2484 const Vec4V V10 = V4Mul(V6, V4);
2485 const Vec4V V12 = V4Mul(V6, V6);
2486 const Vec4V V14 = V4Mul(V8, V6);
2487 const Vec4V V16 = V4Mul(V8, V8);
2488 const Vec4V V18 = V4Mul(V10, V8);
2489 const Vec4V V20 = V4Mul(V10, V10);
2490 const Vec4V V22 = V4Mul(V12, V10);
2491
2492 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
2493 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
2494 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
2495
2496 const FloatV C1 = V4GetY(cosCoefficients0);
2497 const FloatV C2 = V4GetZ(cosCoefficients0);
2498 const FloatV C3 = V4GetW(cosCoefficients0);
2499 const FloatV C4 = V4GetX(cosCoefficients1);
2500 const FloatV C5 = V4GetY(cosCoefficients1);
2501 const FloatV C6 = V4GetZ(cosCoefficients1);
2502 const FloatV C7 = V4GetW(cosCoefficients1);
2503 const FloatV C8 = V4GetX(cosCoefficients2);
2504 const FloatV C9 = V4GetY(cosCoefficients2);
2505 const FloatV C10 = V4GetZ(cosCoefficients2);
2506 const FloatV C11 = V4GetW(cosCoefficients2);
2507
2508 Vec4V Result;
2509 Result = V4ScaleAdd(V2, C1, V4One());
2510 Result = V4ScaleAdd(V4, C2, Result);
2511 Result = V4ScaleAdd(V6, C3, Result);
2512 Result = V4ScaleAdd(V8, C4, Result);
2513 Result = V4ScaleAdd(V10, C5, Result);
2514 Result = V4ScaleAdd(V12, C6, Result);
2515 Result = V4ScaleAdd(V14, C7, Result);
2516 Result = V4ScaleAdd(V16, C8, Result);
2517 Result = V4ScaleAdd(V18, C9, Result);
2518 Result = V4ScaleAdd(V20, C10, Result);
2519 Result = V4ScaleAdd(V22, C11, Result);
2520
2521 return Result;
2522}
2523
2524PX_FORCE_INLINE void V4Transpose(Vec4V& col0, Vec4V& col1, Vec4V& col2, Vec4V& col3)
2525{
2526 const float32x4x2_t v0v1 = vzipq_f32(col0, col2);
2527 const float32x4x2_t v2v3 = vzipq_f32(col1, col3);
2528 const float32x4x2_t zip0 = vzipq_f32(v0v1.val[0], v2v3.val[0]);
2529 const float32x4x2_t zip1 = vzipq_f32(v0v1.val[1], v2v3.val[1]);
2530 col0 = zip0.val[0];
2531 col1 = zip0.val[1];
2532 col2 = zip1.val[0];
2533 col3 = zip1.val[1];
2534}
2535
2537// VEC4V
2539
2540PX_FORCE_INLINE BoolV BFFFF()
2541{
2542 return vmovq_n_u32(0);
2543}
2544
2545PX_FORCE_INLINE BoolV BFFFT()
2546{
2547 const uint32x2_t zeros = vmov_n_u32(0);
2548 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2549 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2550 return vcombine_u32(zeros, zo);
2551}
2552
2553PX_FORCE_INLINE BoolV BFFTF()
2554{
2555 const uint32x2_t zeros = vmov_n_u32(0);
2556 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2557 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2558 return vcombine_u32(zeros, oz);
2559}
2560
2561PX_FORCE_INLINE BoolV BFFTT()
2562{
2563 const uint32x2_t zeros = vmov_n_u32(0);
2564 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2565 return vcombine_u32(zeros, ones);
2566}
2567
2568PX_FORCE_INLINE BoolV BFTFF()
2569{
2570 const uint32x2_t zeros = vmov_n_u32(0);
2571 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2572 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2573 return vcombine_u32(zo, zeros);
2574}
2575
2576PX_FORCE_INLINE BoolV BFTFT()
2577{
2578 const uint32x2_t zeros = vmov_n_u32(0);
2579 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2580 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2581 return vcombine_u32(zo, zo);
2582}
2583
2584PX_FORCE_INLINE BoolV BFTTF()
2585{
2586 const uint32x2_t zeros = vmov_n_u32(0);
2587 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2588 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2589 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2590 return vcombine_u32(zo, oz);
2591}
2592
2593PX_FORCE_INLINE BoolV BFTTT()
2594{
2595 const uint32x2_t zeros = vmov_n_u32(0);
2596 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2597 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2598 return vcombine_u32(zo, ones);
2599}
2600
2601PX_FORCE_INLINE BoolV BTFFF()
2602{
2603 const uint32x2_t zeros = vmov_n_u32(0);
2604 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2605 // const uint32x2_t zo = vext_u32(zeros, ones, 1);
2606 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2607 return vcombine_u32(oz, zeros);
2608}
2609
2610PX_FORCE_INLINE BoolV BTFFT()
2611{
2612 const uint32x2_t zeros = vmov_n_u32(0);
2613 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2614 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2615 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2616 return vcombine_u32(oz, zo);
2617}
2618
2619PX_FORCE_INLINE BoolV BTFTF()
2620{
2621 const uint32x2_t zeros = vmov_n_u32(0);
2622 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2623 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2624 return vcombine_u32(oz, oz);
2625}
2626
2627PX_FORCE_INLINE BoolV BTFTT()
2628{
2629 const uint32x2_t zeros = vmov_n_u32(0);
2630 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2631 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2632 return vcombine_u32(oz, ones);
2633}
2634
2635PX_FORCE_INLINE BoolV BTTFF()
2636{
2637 const uint32x2_t zeros = vmov_n_u32(0);
2638 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2639 return vcombine_u32(ones, zeros);
2640}
2641
2642PX_FORCE_INLINE BoolV BTTFT()
2643{
2644 const uint32x2_t zeros = vmov_n_u32(0);
2645 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2646 const uint32x2_t zo = vext_u32(zeros, ones, 1);
2647 return vcombine_u32(ones, zo);
2648}
2649
2650PX_FORCE_INLINE BoolV BTTTF()
2651{
2652 const uint32x2_t zeros = vmov_n_u32(0);
2653 const uint32x2_t ones = vmov_n_u32(0xffffFFFF);
2654 const uint32x2_t oz = vext_u32(ones, zeros, 1);
2655 return vcombine_u32(ones, oz);
2656}
2657
2658PX_FORCE_INLINE BoolV BTTTT()
2659{
2660 return vmovq_n_u32(0xffffFFFF);
2661}
2662
2663PX_FORCE_INLINE BoolV BXMask()
2664{
2665 return BTFFF();
2666}
2667
2668PX_FORCE_INLINE BoolV BYMask()
2669{
2670 return BFTFF();
2671}
2672
2673PX_FORCE_INLINE BoolV BZMask()
2674{
2675 return BFFTF();
2676}
2677
2678PX_FORCE_INLINE BoolV BWMask()
2679{
2680 return BFFFT();
2681}
2682
2683PX_FORCE_INLINE BoolV BGetX(const BoolV f)
2684{
2685 const uint32x2_t fLow = vget_low_u32(f);
2686 return vdupq_lane_u32(fLow, 0);
2687}
2688
2689PX_FORCE_INLINE BoolV BGetY(const BoolV f)
2690{
2691 const uint32x2_t fLow = vget_low_u32(f);
2692 return vdupq_lane_u32(fLow, 1);
2693}
2694
2695PX_FORCE_INLINE BoolV BGetZ(const BoolV f)
2696{
2697 const uint32x2_t fHigh = vget_high_u32(f);
2698 return vdupq_lane_u32(fHigh, 0);
2699}
2700
2701PX_FORCE_INLINE BoolV BGetW(const BoolV f)
2702{
2703 const uint32x2_t fHigh = vget_high_u32(f);
2704 return vdupq_lane_u32(fHigh, 1);
2705}
2706
2707PX_FORCE_INLINE BoolV BSetX(const BoolV v, const BoolV f)
2708{
2709 return vbslq_u32(BFTTT(), v, f);
2710}
2711
2712PX_FORCE_INLINE BoolV BSetY(const BoolV v, const BoolV f)
2713{
2714 return vbslq_u32(BTFTT(), v, f);
2715}
2716
2717PX_FORCE_INLINE BoolV BSetZ(const BoolV v, const BoolV f)
2718{
2719 return vbslq_u32(BTTFT(), v, f);
2720}
2721
2722PX_FORCE_INLINE BoolV BSetW(const BoolV v, const BoolV f)
2723{
2724 return vbslq_u32(BTTTF(), v, f);
2725}
2726
2727PX_FORCE_INLINE BoolV BAnd(const BoolV a, const BoolV b)
2728{
2729 return vandq_u32(a, b);
2730}
2731
2732PX_FORCE_INLINE BoolV BNot(const BoolV a)
2733{
2734 return vmvnq_u32(a);
2735}
2736
2737PX_FORCE_INLINE BoolV BAndNot(const BoolV a, const BoolV b)
2738{
2739 // return vbicq_u32(a, b);
2740 return vandq_u32(a, vmvnq_u32(b));
2741}
2742
2743PX_FORCE_INLINE BoolV BOr(const BoolV a, const BoolV b)
2744{
2745 return vorrq_u32(a, b);
2746}
2747
2748PX_FORCE_INLINE BoolV BAllTrue4(const BoolV a)
2749{
2750 const uint32x2_t allTrue = vmov_n_u32(0xffffFFFF);
2751 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
2752 const uint16x4_t dLow = vmovn_u32(a);
2753 uint16x8_t combined = vcombine_u16(dLow, dHigh);
2754 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
2755 const uint32x2_t result = vceq_u32(finalReduce, allTrue);
2756 return vdupq_lane_u32(result, 0);
2757}
2758
2759PX_FORCE_INLINE BoolV BAnyTrue4(const BoolV a)
2760{
2761 const uint32x2_t allTrue = vmov_n_u32(0xffffFFFF);
2762 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
2763 const uint16x4_t dLow = vmovn_u32(a);
2764 uint16x8_t combined = vcombine_u16(dLow, dHigh);
2765 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
2766 const uint32x2_t result = vtst_u32(finalReduce, allTrue);
2767 return vdupq_lane_u32(result, 0);
2768}
2769
2770PX_FORCE_INLINE BoolV BAllTrue3(const BoolV a)
2771{
2772 const uint32x2_t allTrue3 = vmov_n_u32(0x00ffFFFF);
2773 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
2774 const uint16x4_t dLow = vmovn_u32(a);
2775 uint16x8_t combined = vcombine_u16(dLow, dHigh);
2776 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
2777 const uint32x2_t result = vceq_u32(vand_u32(finalReduce, allTrue3), allTrue3);
2778 return vdupq_lane_u32(result, 0);
2779}
2780
2781PX_FORCE_INLINE BoolV BAnyTrue3(const BoolV a)
2782{
2783 const uint32x2_t allTrue3 = vmov_n_u32(0x00ffFFFF);
2784 const uint16x4_t dHigh = vget_high_u16(vreinterpretq_u16_u32(a));
2785 const uint16x4_t dLow = vmovn_u32(a);
2786 uint16x8_t combined = vcombine_u16(dLow, dHigh);
2787 const uint32x2_t finalReduce = vreinterpret_u32_u8(vmovn_u16(combined));
2788 const uint32x2_t result = vtst_u32(vand_u32(finalReduce, allTrue3), allTrue3);
2789 return vdupq_lane_u32(result, 0);
2790}
2791
2792PX_FORCE_INLINE PxU32 BAllEq(const BoolV a, const BoolV b)
2793{
2794 const BoolV bTest = vceqq_u32(a, b);
2795 return internalUnitNeonSimd::BAllTrue4_R(bTest);
2796}
2797
2798PX_FORCE_INLINE PxU32 BAllEqTTTT(const BoolV a)
2799{
2800 return BAllEq(a, BTTTT());
2801}
2802
2803PX_FORCE_INLINE PxU32 BAllEqFFFF(const BoolV a)
2804{
2805 return BAllEq(a, BFFFF());
2806}
2807
2808PX_FORCE_INLINE PxU32 BGetBitMask(const BoolV a)
2809{
2810 static PX_ALIGN(16, const PxU32) bitMaskData[4] = { 1, 2, 4, 8 };
2811 const uint32x4_t bitMask = *(reinterpret_cast<const uint32x4_t*>(bitMaskData));
2812 const uint32x4_t t0 = vandq_u32(a, bitMask);
2813 const uint32x2_t t1 = vpadd_u32(vget_low_u32(t0), vget_high_u32(t0)); // Pairwise add (0 + 1), (2 + 3)
2814 return PxU32(vget_lane_u32(vpadd_u32(t1, t1), 0));
2815}
2816
2818// MAT33V
2820
2821PX_FORCE_INLINE Vec3V M33MulV3(const Mat33V& a, const Vec3V b)
2822{
2823 const FloatV x = V3GetX(b);
2824 const FloatV y = V3GetY(b);
2825 const FloatV z = V3GetZ(b);
2826 const Vec3V v0 = V3Scale(a.col0, x);
2827 const Vec3V v1 = V3Scale(a.col1, y);
2828 const Vec3V v2 = V3Scale(a.col2, z);
2829 const Vec3V v0PlusV1 = V3Add(v0, v1);
2830 return V3Add(v0PlusV1, v2);
2831}
2832
2833PX_FORCE_INLINE Vec3V M33TrnspsMulV3(const Mat33V& a, const Vec3V b)
2834{
2835 const FloatV x = V3Dot(a.col0, b);
2836 const FloatV y = V3Dot(a.col1, b);
2837 const FloatV z = V3Dot(a.col2, b);
2838 return V3Merge(x, y, z);
2839}
2840
2841PX_FORCE_INLINE Vec3V M33MulV3AddV3(const Mat33V& A, const Vec3V b, const Vec3V c)
2842{
2843 const FloatV x = V3GetX(b);
2844 const FloatV y = V3GetY(b);
2845 const FloatV z = V3GetZ(b);
2846 Vec3V result = V3ScaleAdd(A.col0, x, c);
2847 result = V3ScaleAdd(A.col1, y, result);
2848 return V3ScaleAdd(A.col2, z, result);
2849}
2850
2851PX_FORCE_INLINE Mat33V M33MulM33(const Mat33V& a, const Mat33V& b)
2852{
2853 return Mat33V(M33MulV3(a, b.col0), M33MulV3(a, b.col1), M33MulV3(a, b.col2));
2854}
2855
2856PX_FORCE_INLINE Mat33V M33Add(const Mat33V& a, const Mat33V& b)
2857{
2858 return Mat33V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2));
2859}
2860
2861PX_FORCE_INLINE Mat33V M33Scale(const Mat33V& a, const FloatV& b)
2862{
2863 return Mat33V(V3Scale(a.col0, b), V3Scale(a.col1, b), V3Scale(a.col2, b));
2864}
2865
2866PX_FORCE_INLINE Mat33V M33Inverse(const Mat33V& a)
2867{
2868 const float32x2_t zeros = vreinterpret_f32_u32(vmov_n_u32(0));
2869 const BoolV btttf = BTTTF();
2870
2871 const Vec3V cross01 = V3Cross(a.col0, a.col1);
2872 const Vec3V cross12 = V3Cross(a.col1, a.col2);
2873 const Vec3V cross20 = V3Cross(a.col2, a.col0);
2874 const FloatV dot = V3Dot(cross01, a.col2);
2875 const FloatV invDet = FRecipFast(dot);
2876
2877 const float32x4x2_t merge = vzipq_f32(cross12, cross01);
2878 const float32x4_t mergeh = merge.val[0];
2879 const float32x4_t mergel = merge.val[1];
2880
2881 // const Vec3V colInv0 = XMVectorPermute(mergeh,cross20,PxPermuteControl(0,4,1,7));
2882 const float32x4_t colInv0_xxyy = vzipq_f32(mergeh, cross20).val[0];
2883 const float32x4_t colInv0 = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(colInv0_xxyy), btttf));
2884
2885 // const Vec3V colInv1 = XMVectorPermute(mergeh,cross20,PxPermuteControl(2,5,3,7));
2886 const float32x2_t zw0 = vget_high_f32(mergeh);
2887 const float32x2_t xy1 = vget_low_f32(cross20);
2888 const float32x2_t yzero1 = vext_f32(xy1, zeros, 1);
2889 const float32x2x2_t merge1 = vzip_f32(zw0, yzero1);
2890 const float32x4_t colInv1 = vcombine_f32(merge1.val[0], merge1.val[1]);
2891
2892 // const Vec3V colInv2 = XMVectorPermute(mergel,cross20,PxPermuteControl(0,6,1,7));
2893 const float32x2_t x0y0 = vget_low_f32(mergel);
2894 const float32x2_t z1w1 = vget_high_f32(cross20);
2895 const float32x2x2_t merge2 = vzip_f32(x0y0, z1w1);
2896 const float32x4_t colInv2 = vcombine_f32(merge2.val[0], merge2.val[1]);
2897
2898 return Mat33V(vmulq_lane_f32(colInv0, invDet, 0), vmulq_lane_f32(colInv1, invDet, 0),
2899 vmulq_lane_f32(colInv2, invDet, 0));
2900}
2901
2902PX_FORCE_INLINE Mat33V M33Trnsps(const Mat33V& a)
2903{
2904 return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
2905 V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
2906 V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
2907}
2908
2909PX_FORCE_INLINE Mat33V M33Identity()
2910{
2911 return Mat33V(V3UnitX(), V3UnitY(), V3UnitZ());
2912}
2913
2914PX_FORCE_INLINE Mat33V M33Sub(const Mat33V& a, const Mat33V& b)
2915{
2916 return Mat33V(V3Sub(a.col0, b.col0), V3Sub(a.col1, b.col1), V3Sub(a.col2, b.col2));
2917}
2918
2919PX_FORCE_INLINE Mat33V M33Neg(const Mat33V& a)
2920{
2921 return Mat33V(V3Neg(a.col0), V3Neg(a.col1), V3Neg(a.col2));
2922}
2923
2924PX_FORCE_INLINE Mat33V M33Abs(const Mat33V& a)
2925{
2926 return Mat33V(V3Abs(a.col0), V3Abs(a.col1), V3Abs(a.col2));
2927}
2928
2929PX_FORCE_INLINE Mat33V PromoteVec3V(const Vec3V v)
2930{
2931 const BoolV bTFFF = BTFFF();
2932 const BoolV bFTFF = BFTFF();
2933 const BoolV bFFTF = BTFTF();
2934
2935 const Vec3V zero = V3Zero();
2936
2937 return Mat33V(V3Sel(bTFFF, v, zero), V3Sel(bFTFF, v, zero), V3Sel(bFFTF, v, zero));
2938}
2939
2940PX_FORCE_INLINE Mat33V M33Diagonal(const Vec3VArg d)
2941{
2942 const Vec3V x = V3Mul(V3UnitX(), d);
2943 const Vec3V y = V3Mul(V3UnitY(), d);
2944 const Vec3V z = V3Mul(V3UnitZ(), d);
2945 return Mat33V(x, y, z);
2946}
2947
2949// MAT34V
2951
2952PX_FORCE_INLINE Vec3V M34MulV3(const Mat34V& a, const Vec3V b)
2953{
2954 const FloatV x = V3GetX(b);
2955 const FloatV y = V3GetY(b);
2956 const FloatV z = V3GetZ(b);
2957 const Vec3V v0 = V3Scale(a.col0, x);
2958 const Vec3V v1 = V3Scale(a.col1, y);
2959 const Vec3V v2 = V3Scale(a.col2, z);
2960 const Vec3V v0PlusV1 = V3Add(v0, v1);
2961 const Vec3V v0PlusV1Plusv2 = V3Add(v0PlusV1, v2);
2962 return V3Add(v0PlusV1Plusv2, a.col3);
2963}
2964
2965PX_FORCE_INLINE Vec3V M34Mul33V3(const Mat34V& a, const Vec3V b)
2966{
2967 const FloatV x = V3GetX(b);
2968 const FloatV y = V3GetY(b);
2969 const FloatV z = V3GetZ(b);
2970 const Vec3V v0 = V3Scale(a.col0, x);
2971 const Vec3V v1 = V3Scale(a.col1, y);
2972 const Vec3V v2 = V3Scale(a.col2, z);
2973 const Vec3V v0PlusV1 = V3Add(v0, v1);
2974 return V3Add(v0PlusV1, v2);
2975}
2976
2977PX_FORCE_INLINE Vec3V M34TrnspsMul33V3(const Mat34V& a, const Vec3V b)
2978{
2979 const FloatV x = V3Dot(a.col0, b);
2980 const FloatV y = V3Dot(a.col1, b);
2981 const FloatV z = V3Dot(a.col2, b);
2982 return V3Merge(x, y, z);
2983}
2984
2985PX_FORCE_INLINE Mat34V M34MulM34(const Mat34V& a, const Mat34V& b)
2986{
2987 return Mat34V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2), M34MulV3(a, b.col3));
2988}
2989
2990PX_FORCE_INLINE Mat33V M34MulM33(const Mat34V& a, const Mat33V& b)
2991{
2992 return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
2993}
2994
2995PX_FORCE_INLINE Mat33V M34Mul33MM34(const Mat34V& a, const Mat34V& b)
2996{
2997 return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
2998}
2999
3000PX_FORCE_INLINE Mat34V M34Add(const Mat34V& a, const Mat34V& b)
3001{
3002 return Mat34V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2), V3Add(a.col3, b.col3));
3003}
3004
3005PX_FORCE_INLINE Mat33V M34Trnsps33(const Mat34V& a)
3006{
3007 return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
3008 V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
3009 V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
3010}
3011
3013// MAT44V
3015
3016PX_FORCE_INLINE Vec4V M44MulV4(const Mat44V& a, const Vec4V b)
3017{
3018 const FloatV x = V4GetX(b);
3019 const FloatV y = V4GetY(b);
3020 const FloatV z = V4GetZ(b);
3021 const FloatV w = V4GetW(b);
3022
3023 const Vec4V v0 = V4Scale(a.col0, x);
3024 const Vec4V v1 = V4Scale(a.col1, y);
3025 const Vec4V v2 = V4Scale(a.col2, z);
3026 const Vec4V v3 = V4Scale(a.col3, w);
3027 const Vec4V v0PlusV1 = V4Add(v0, v1);
3028 const Vec4V v0PlusV1Plusv2 = V4Add(v0PlusV1, v2);
3029 return V4Add(v0PlusV1Plusv2, v3);
3030}
3031
3032PX_FORCE_INLINE Vec4V M44TrnspsMulV4(const Mat44V& a, const Vec4V b)
3033{
3034 return V4Merge(V4Dot(a.col0, b), V4Dot(a.col1, b), V4Dot(a.col2, b), V4Dot(a.col3, b));
3035}
3036
3037PX_FORCE_INLINE Mat44V M44MulM44(const Mat44V& a, const Mat44V& b)
3038{
3039 return Mat44V(M44MulV4(a, b.col0), M44MulV4(a, b.col1), M44MulV4(a, b.col2), M44MulV4(a, b.col3));
3040}
3041
3042PX_FORCE_INLINE Mat44V M44Add(const Mat44V& a, const Mat44V& b)
3043{
3044 return Mat44V(V4Add(a.col0, b.col0), V4Add(a.col1, b.col1), V4Add(a.col2, b.col2), V4Add(a.col3, b.col3));
3045}
3046
3047PX_FORCE_INLINE Mat44V M44Trnsps(const Mat44V& a)
3048{
3049 // asm volatile(
3050 // "vzip.f32 %q0, %q2 \n\t"
3051 // "vzip.f32 %q1, %q3 \n\t"
3052 // "vzip.f32 %q0, %q1 \n\t"
3053 // "vzip.f32 %q2, %q3 \n\t"
3054 // : "+w" (a.col0), "+w" (a.col1), "+w" (a.col2), "+w" a.col3));
3055
3056 const float32x4x2_t v0v1 = vzipq_f32(a.col0, a.col2);
3057 const float32x4x2_t v2v3 = vzipq_f32(a.col1, a.col3);
3058 const float32x4x2_t zip0 = vzipq_f32(v0v1.val[0], v2v3.val[0]);
3059 const float32x4x2_t zip1 = vzipq_f32(v0v1.val[1], v2v3.val[1]);
3060
3061 return Mat44V(zip0.val[0], zip0.val[1], zip1.val[0], zip1.val[1]);
3062}
3063
3064PX_FORCE_INLINE Mat44V M44Inverse(const Mat44V& a)
3065{
3066 float32x4_t minor0, minor1, minor2, minor3;
3067 float32x4_t row0, row1, row2, row3;
3068 float32x4_t det, tmp1;
3069
3070 tmp1 = vmovq_n_f32(0.0f);
3071 row1 = vmovq_n_f32(0.0f);
3072 row3 = vmovq_n_f32(0.0f);
3073
3074 row0 = a.col0;
3075 row1 = vextq_f32(a.col1, a.col1, 2);
3076 row2 = a.col2;
3077 row3 = vextq_f32(a.col3, a.col3, 2);
3078
3079 tmp1 = vmulq_f32(row2, row3);
3080 tmp1 = vrev64q_f32(tmp1);
3081 minor0 = vmulq_f32(row1, tmp1);
3082 minor1 = vmulq_f32(row0, tmp1);
3083 tmp1 = vextq_f32(tmp1, tmp1, 2);
3084 minor0 = vsubq_f32(vmulq_f32(row1, tmp1), minor0);
3085 minor1 = vsubq_f32(vmulq_f32(row0, tmp1), minor1);
3086 minor1 = vextq_f32(minor1, minor1, 2);
3087
3088 tmp1 = vmulq_f32(row1, row2);
3089 tmp1 = vrev64q_f32(tmp1);
3090 minor0 = vaddq_f32(vmulq_f32(row3, tmp1), minor0);
3091 minor3 = vmulq_f32(row0, tmp1);
3092 tmp1 = vextq_f32(tmp1, tmp1, 2);
3093 minor0 = vsubq_f32(minor0, vmulq_f32(row3, tmp1));
3094 minor3 = vsubq_f32(vmulq_f32(row0, tmp1), minor3);
3095 minor3 = vextq_f32(minor3, minor3, 2);
3096
3097 tmp1 = vmulq_f32(vextq_f32(row1, row1, 2), row3);
3098 tmp1 = vrev64q_f32(tmp1);
3099 row2 = vextq_f32(row2, row2, 2);
3100 minor0 = vaddq_f32(vmulq_f32(row2, tmp1), minor0);
3101 minor2 = vmulq_f32(row0, tmp1);
3102 tmp1 = vextq_f32(tmp1, tmp1, 2);
3103 minor0 = vsubq_f32(minor0, vmulq_f32(row2, tmp1));
3104 minor2 = vsubq_f32(vmulq_f32(row0, tmp1), minor2);
3105 minor2 = vextq_f32(minor2, minor2, 2);
3106
3107 tmp1 = vmulq_f32(row0, row1);
3108 tmp1 = vrev64q_f32(tmp1);
3109 minor2 = vaddq_f32(vmulq_f32(row3, tmp1), minor2);
3110 minor3 = vsubq_f32(vmulq_f32(row2, tmp1), minor3);
3111 tmp1 = vextq_f32(tmp1, tmp1, 2);
3112 minor2 = vsubq_f32(vmulq_f32(row3, tmp1), minor2);
3113 minor3 = vsubq_f32(minor3, vmulq_f32(row2, tmp1));
3114
3115 tmp1 = vmulq_f32(row0, row3);
3116 tmp1 = vrev64q_f32(tmp1);
3117 minor1 = vsubq_f32(minor1, vmulq_f32(row2, tmp1));
3118 minor2 = vaddq_f32(vmulq_f32(row1, tmp1), minor2);
3119 tmp1 = vextq_f32(tmp1, tmp1, 2);
3120 minor1 = vaddq_f32(vmulq_f32(row2, tmp1), minor1);
3121 minor2 = vsubq_f32(minor2, vmulq_f32(row1, tmp1));
3122
3123 tmp1 = vmulq_f32(row0, row2);
3124 tmp1 = vrev64q_f32(tmp1);
3125 minor1 = vaddq_f32(vmulq_f32(row3, tmp1), minor1);
3126 minor3 = vsubq_f32(minor3, vmulq_f32(row1, tmp1));
3127 tmp1 = vextq_f32(tmp1, tmp1, 2);
3128 minor1 = vsubq_f32(minor1, vmulq_f32(row3, tmp1));
3129 minor3 = vaddq_f32(vmulq_f32(row1, tmp1), minor3);
3130
3131 det = vmulq_f32(row0, minor0);
3132 det = vaddq_f32(vextq_f32(det, det, 2), det);
3133 det = vaddq_f32(vrev64q_f32(det), det);
3134 det = vdupq_lane_f32(VRECIPE(vget_low_f32(det)), 0);
3135
3136 minor0 = vmulq_f32(det, minor0);
3137 minor1 = vmulq_f32(det, minor1);
3138 minor2 = vmulq_f32(det, minor2);
3139 minor3 = vmulq_f32(det, minor3);
3140 Mat44V invTrans(minor0, minor1, minor2, minor3);
3141 return M44Trnsps(invTrans);
3142}
3143
3144PX_FORCE_INLINE Vec4V V4LoadXYZW(const PxF32& x, const PxF32& y, const PxF32& z, const PxF32& w)
3145{
3146 const float32x4_t ret = { x, y, z, w };
3147 return ret;
3148}
3149
3150/*
3151PX_FORCE_INLINE VecU16V V4U32PK(VecU32V a, VecU32V b)
3152{
3153 return vcombine_u16(vqmovn_u32(a), vqmovn_u32(b));
3154}
3155*/
3156
3157PX_FORCE_INLINE VecU32V V4U32Sel(const BoolV c, const VecU32V a, const VecU32V b)
3158{
3159 return vbslq_u32(c, a, b);
3160}
3161
3162PX_FORCE_INLINE VecU32V V4U32or(VecU32V a, VecU32V b)
3163{
3164 return vorrq_u32(a, b);
3165}
3166
3167PX_FORCE_INLINE VecU32V V4U32xor(VecU32V a, VecU32V b)
3168{
3169 return veorq_u32(a, b);
3170}
3171
3172PX_FORCE_INLINE VecU32V V4U32and(VecU32V a, VecU32V b)
3173{
3174 return vandq_u32(a, b);
3175}
3176
3177PX_FORCE_INLINE VecU32V V4U32Andc(VecU32V a, VecU32V b)
3178{
3179 // return vbicq_u32(a, b); // creates gcc compiler bug in RTreeQueries.cpp
3180 return vandq_u32(a, vmvnq_u32(b));
3181}
3182
3183/*
3184PX_FORCE_INLINE VecU16V V4U16Or(VecU16V a, VecU16V b)
3185{
3186 return vorrq_u16(a, b);
3187}
3188*/
3189
3190/*
3191PX_FORCE_INLINE VecU16V V4U16And(VecU16V a, VecU16V b)
3192{
3193 return vandq_u16(a, b);
3194}
3195*/
3196/*
3197PX_FORCE_INLINE VecU16V V4U16Andc(VecU16V a, VecU16V b)
3198{
3199 return vbicq_u16(a, b);
3200}
3201*/
3202
3203PX_FORCE_INLINE VecI32V I4LoadXYZW(const PxI32& x, const PxI32& y, const PxI32& z, const PxI32& w)
3204{
3205 const int32x4_t ret = { x, y, z, w };
3206 return ret;
3207}
3208
3209PX_FORCE_INLINE VecI32V I4Load(const PxI32 i)
3210{
3211 return vdupq_n_s32(i);
3212}
3213
3214PX_FORCE_INLINE VecI32V I4LoadU(const PxI32* i)
3215{
3216 return vld1q_s32(i);
3217}
3218
3219PX_FORCE_INLINE VecI32V I4LoadA(const PxI32* i)
3220{
3221 return vld1q_s32(i);
3222}
3223
3224PX_FORCE_INLINE VecI32V VecI32V_Add(const VecI32VArg a, const VecI32VArg b)
3225{
3226 return vaddq_s32(a, b);
3227}
3228
3229PX_FORCE_INLINE VecI32V VecI32V_Sub(const VecI32VArg a, const VecI32VArg b)
3230{
3231 return vsubq_s32(a, b);
3232}
3233
3234PX_FORCE_INLINE BoolV VecI32V_IsGrtr(const VecI32VArg a, const VecI32VArg b)
3235{
3236 return vcgtq_s32(a, b);
3237}
3238
3239PX_FORCE_INLINE BoolV VecI32V_IsEq(const VecI32VArg a, const VecI32VArg b)
3240{
3241 return vceqq_s32(a, b);
3242}
3243
3244PX_FORCE_INLINE VecI32V V4I32Sel(const BoolV c, const VecI32V a, const VecI32V b)
3245{
3246 return vbslq_s32(c, a, b);
3247}
3248
3249PX_FORCE_INLINE VecI32V VecI32V_Zero()
3250{
3251 return vdupq_n_s32(0);
3252}
3253
3254PX_FORCE_INLINE VecI32V VecI32V_One()
3255{
3256 return vdupq_n_s32(1);
3257}
3258
3259PX_FORCE_INLINE VecI32V VecI32V_Two()
3260{
3261 return vdupq_n_s32(2);
3262}
3263
3264PX_FORCE_INLINE VecI32V VecI32V_MinusOne()
3265{
3266 return vdupq_n_s32(-1);
3267}
3268
3269PX_FORCE_INLINE VecU32V U4Zero()
3270{
3271 return U4Load(0);
3272}
3273
3274PX_FORCE_INLINE VecU32V U4One()
3275{
3276 return U4Load(1);
3277}
3278
3279PX_FORCE_INLINE VecU32V U4Two()
3280{
3281 return U4Load(2);
3282}
3283
3284PX_FORCE_INLINE VecShiftV VecI32V_PrepareShift(const VecI32VArg shift)
3285{
3286 return shift;
3287}
3288
3289PX_FORCE_INLINE VecI32V VecI32V_LeftShift(const VecI32VArg a, const VecShiftVArg count)
3290{
3291 return vshlq_s32(a, count);
3292}
3293
3294PX_FORCE_INLINE VecI32V VecI32V_RightShift(const VecI32VArg a, const VecShiftVArg count)
3295{
3296 return vshlq_s32(a, VecI32V_Sub(I4Load(0), count));
3297}
3298
3299PX_FORCE_INLINE VecI32V VecI32V_LeftShift(const VecI32VArg a, const PxU32 count)
3300{
3301 const int32x4_t shiftCount = { (PxI32)count, (PxI32)count, (PxI32)count, (PxI32)count };
3302 return vshlq_s32(a, shiftCount);
3303}
3304
3305PX_FORCE_INLINE VecI32V VecI32V_RightShift(const VecI32VArg a, const PxU32 count)
3306{
3307 const int32x4_t shiftCount = { -(PxI32)count, -(PxI32)count, -(PxI32)count, -(PxI32)count };
3308 return vshlq_s32(a, shiftCount);
3309}
3310
3311PX_FORCE_INLINE VecI32V VecI32V_And(const VecI32VArg a, const VecI32VArg b)
3312{
3313 return vandq_s32(a, b);
3314}
3315
3316PX_FORCE_INLINE VecI32V VecI32V_Or(const VecI32VArg a, const VecI32VArg b)
3317{
3318 return vorrq_s32(a, b);
3319}
3320
3321PX_FORCE_INLINE VecI32V VecI32V_GetX(const VecI32VArg f)
3322{
3323 const int32x2_t fLow = vget_low_s32(f);
3324 return vdupq_lane_s32(fLow, 0);
3325}
3326
3327PX_FORCE_INLINE VecI32V VecI32V_GetY(const VecI32VArg f)
3328{
3329 const int32x2_t fLow = vget_low_s32(f);
3330 return vdupq_lane_s32(fLow, 1);
3331}
3332
3333PX_FORCE_INLINE VecI32V VecI32V_GetZ(const VecI32VArg f)
3334{
3335 const int32x2_t fHigh = vget_high_s32(f);
3336 return vdupq_lane_s32(fHigh, 0);
3337}
3338
3339PX_FORCE_INLINE VecI32V VecI32V_GetW(const VecI32VArg f)
3340{
3341 const int32x2_t fHigh = vget_high_s32(f);
3342 return vdupq_lane_s32(fHigh, 1);
3343}
3344
3345PX_FORCE_INLINE VecI32V VecI32V_Sel(const BoolV c, const VecI32VArg a, const VecI32VArg b)
3346{
3347 return vbslq_s32(c, a, b);
3348}
3349
3350PX_FORCE_INLINE void PxI32_From_VecI32V(const VecI32VArg a, PxI32* i)
3351{
3352 *i = vgetq_lane_s32(a, 0);
3353}
3354
3355PX_FORCE_INLINE VecI32V VecI32V_Merge(const VecI32VArg a, const VecI32VArg b, const VecI32VArg c, const VecI32VArg d)
3356{
3357 const int32x2_t aLow = vget_low_s32(a);
3358 const int32x2_t bLow = vget_low_s32(b);
3359 const int32x2_t cLow = vget_low_s32(c);
3360 const int32x2_t dLow = vget_low_s32(d);
3361
3362 const int32x2_t low = vext_s32(aLow, bLow, 1);
3363 const int32x2_t high = vext_s32(cLow, dLow, 1);
3364
3365 return vcombine_s32(low, high);
3366}
3367
3368PX_FORCE_INLINE VecI32V VecI32V_From_BoolV(const BoolVArg a)
3369{
3370 return vreinterpretq_s32_u32(a);
3371}
3372
3373PX_FORCE_INLINE VecU32V VecU32V_From_BoolV(const BoolVArg a)
3374{
3375 return a;
3376}
3377
3378/*
3379template<int a> PX_FORCE_INLINE VecI32V V4ISplat()
3380{
3381 return vdupq_n_s32(a);
3382}
3383
3384template<PxU32 a> PX_FORCE_INLINE VecU32V V4USplat()
3385{
3386 return vdupq_n_u32(a);
3387}
3388*/
3389
3390/*
3391PX_FORCE_INLINE void V4U16StoreAligned(VecU16V val, VecU16V* address)
3392{
3393 vst1q_u16((uint16_t*)address, val);
3394}
3395*/
3396
3397PX_FORCE_INLINE void V4U32StoreAligned(VecU32V val, VecU32V* address)
3398{
3399 vst1q_u32(reinterpret_cast<uint32_t*>(address), val);
3400}
3401
3402PX_FORCE_INLINE Vec4V V4LoadAligned(Vec4V* addr)
3403{
3404 return vld1q_f32(reinterpret_cast<float32_t*>(addr));
3405}
3406
3407PX_FORCE_INLINE Vec4V V4LoadUnaligned(Vec4V* addr)
3408{
3409 return vld1q_f32(reinterpret_cast<float32_t*>(addr));
3410}
3411
3412PX_FORCE_INLINE Vec4V V4Andc(const Vec4V a, const VecU32V b)
3413{
3414 return vreinterpretq_f32_u32(V4U32Andc(vreinterpretq_u32_f32(a), b));
3415}
3416
3417PX_FORCE_INLINE VecU32V V4IsGrtrV32u(const Vec4V a, const Vec4V b)
3418{
3419 return V4IsGrtr(a, b);
3420}
3421
3422PX_FORCE_INLINE VecU16V V4U16LoadAligned(VecU16V* addr)
3423{
3424 return vld1q_u16(reinterpret_cast<uint16_t*>(addr));
3425}
3426
3427PX_FORCE_INLINE VecU16V V4U16LoadUnaligned(VecU16V* addr)
3428{
3429 return vld1q_u16(reinterpret_cast<uint16_t*>(addr));
3430}
3431
3432PX_FORCE_INLINE VecU16V V4U16CompareGt(VecU16V a, VecU16V b)
3433{
3434 return vcgtq_u16(a, b);
3435}
3436
3437PX_FORCE_INLINE VecU16V V4I16CompareGt(VecI16V a, VecI16V b)
3438{
3439 return vcgtq_s16(a, b);
3440}
3441
3442PX_FORCE_INLINE Vec4V Vec4V_From_VecU32V(VecU32V a)
3443{
3444 return vcvtq_f32_u32(a);
3445}
3446
3447PX_FORCE_INLINE Vec4V Vec4V_From_VecI32V(VecI32V a)
3448{
3449 return vcvtq_f32_s32(a);
3450}
3451
3452PX_FORCE_INLINE VecI32V VecI32V_From_Vec4V(Vec4V a)
3453{
3454 return vcvtq_s32_f32(a);
3455}
3456
3457PX_FORCE_INLINE Vec4V Vec4V_ReinterpretFrom_VecU32V(VecU32V a)
3458{
3459 return vreinterpretq_f32_u32(a);
3460}
3461
3462PX_FORCE_INLINE Vec4V Vec4V_ReinterpretFrom_VecI32V(VecI32V a)
3463{
3464 return vreinterpretq_f32_s32(a);
3465}
3466
3467PX_FORCE_INLINE VecU32V VecU32V_ReinterpretFrom_Vec4V(Vec4V a)
3468{
3469 return vreinterpretq_u32_f32(a);
3470}
3471
3472PX_FORCE_INLINE VecI32V VecI32V_ReinterpretFrom_Vec4V(Vec4V a)
3473{
3474 return vreinterpretq_s32_f32(a);
3475}
3476
3477#if !PX_SWITCH
3478template <int index>
3479PX_FORCE_INLINE BoolV BSplatElement(BoolV a)
3480{
3481 if(index < 2)
3482 {
3483 return vdupq_lane_u32(vget_low_u32(a), index);
3484 }
3485 else if(index == 2)
3486 {
3487 return vdupq_lane_u32(vget_high_u32(a), 0);
3488 }
3489 else if(index == 3)
3490 {
3491 return vdupq_lane_u32(vget_high_u32(a), 1);
3492 }
3493}
3494#else
3495//workaround for template compile issue
3496template <int index> PX_FORCE_INLINE BoolV BSplatElement(BoolV a);
3497template<> PX_FORCE_INLINE BoolV BSplatElement<0>(BoolV a) { return vdupq_lane_u32(vget_low_u32(a), 0); }
3498template<> PX_FORCE_INLINE BoolV BSplatElement<1>(BoolV a) { return vdupq_lane_u32(vget_low_u32(a), 1); }
3499template<> PX_FORCE_INLINE BoolV BSplatElement<2>(BoolV a) { return vdupq_lane_u32(vget_high_u32(a), 0); }
3500template<> PX_FORCE_INLINE BoolV BSplatElement<3>(BoolV a) { return vdupq_lane_u32(vget_high_u32(a), 1); }
3501#endif
3502
3503#if !PX_SWITCH
3504template <int index>
3505PX_FORCE_INLINE VecU32V V4U32SplatElement(VecU32V a)
3506{
3507 if(index < 2)
3508 {
3509 return vdupq_lane_u32(vget_low_u32(a), index);
3510 }
3511 else if(index == 2)
3512 {
3513 return vdupq_lane_u32(vget_high_u32(a), 0);
3514 }
3515 else if(index == 3)
3516 {
3517 return vdupq_lane_u32(vget_high_u32(a), 1);
3518 }
3519}
3520#else
3521//workaround for template compile issue
3522template <int index> PX_FORCE_INLINE VecU32V V4U32SplatElement(VecU32V a);
3523template <> PX_FORCE_INLINE VecU32V V4U32SplatElement<0>(VecU32V a) { return vdupq_lane_u32(vget_low_u32(a), 0); }
3524template <> PX_FORCE_INLINE VecU32V V4U32SplatElement<1>(VecU32V a) { return vdupq_lane_u32(vget_low_u32(a), 1); }
3525template <> PX_FORCE_INLINE VecU32V V4U32SplatElement<2>(VecU32V a) { return vdupq_lane_u32(vget_high_u32(a), 0); }
3526template <> PX_FORCE_INLINE VecU32V V4U32SplatElement<3>(VecU32V a) { return vdupq_lane_u32(vget_high_u32(a), 1); }
3527#endif
3528
3529#if !PX_SWITCH
3530template <int index>
3531PX_FORCE_INLINE Vec4V V4SplatElement(Vec4V a)
3532{
3533 if(index < 2)
3534 {
3535 return vdupq_lane_f32(vget_low_f32(a), index);
3536 }
3537 else if(index == 2)
3538 {
3539 return vdupq_lane_f32(vget_high_f32(a), 0);
3540 }
3541 else if(index == 3)
3542 {
3543 return vdupq_lane_f32(vget_high_f32(a), 1);
3544 }
3545}
3546#else
3547//workaround for template compile issue
3548template <int index> PX_FORCE_INLINE Vec4V V4SplatElement(Vec4V a);
3549template <> PX_FORCE_INLINE Vec4V V4SplatElement<0>(Vec4V a) { return vdupq_lane_f32(vget_low_f32(a), 0); }
3550template <> PX_FORCE_INLINE Vec4V V4SplatElement<1>(Vec4V a) { return vdupq_lane_f32(vget_low_f32(a), 1); }
3551template <> PX_FORCE_INLINE Vec4V V4SplatElement<2>(Vec4V a) { return vdupq_lane_f32(vget_high_f32(a), 0); }
3552template <> PX_FORCE_INLINE Vec4V V4SplatElement<3>(Vec4V a) { return vdupq_lane_f32(vget_high_f32(a), 1); }
3553#endif
3554
3555PX_FORCE_INLINE VecU32V U4LoadXYZW(PxU32 x, PxU32 y, PxU32 z, PxU32 w)
3556{
3557 const uint32x4_t ret = { x, y, z, w };
3558 return ret;
3559}
3560
3561PX_FORCE_INLINE VecU32V U4Load(const PxU32 i)
3562{
3563 return vdupq_n_u32(i);
3564}
3565
3566PX_FORCE_INLINE VecU32V U4LoadU(const PxU32* i)
3567{
3568 return vld1q_u32(i);
3569}
3570
3571PX_FORCE_INLINE VecU32V U4LoadA(const PxU32* i)
3572{
3573 return vld1q_u32(i);
3574}
3575
3576PX_FORCE_INLINE Vec4V V4Ceil(const Vec4V in)
3577{
3578 const float32x4_t ones = vdupq_n_f32(1.0f);
3579 const float32x4_t rdToZero = vcvtq_f32_s32(vcvtq_s32_f32(in));
3580 const float32x4_t rdToZeroPlusOne = vaddq_f32(rdToZero, ones);
3581 const uint32x4_t gt = vcgtq_f32(in, rdToZero);
3582 return vbslq_f32(gt, rdToZeroPlusOne, rdToZero);
3583}
3584
3585PX_FORCE_INLINE Vec4V V4Floor(const Vec4V in)
3586{
3587 const float32x4_t ones = vdupq_n_f32(1.0f);
3588 const float32x4_t rdToZero = vcvtq_f32_s32(vcvtq_s32_f32(in));
3589 const float32x4_t rdToZeroMinusOne = vsubq_f32(rdToZero, ones);
3590 const uint32x4_t lt = vcltq_f32(in, rdToZero);
3591 return vbslq_f32(lt, rdToZeroMinusOne, rdToZero);
3592}
3593
3594PX_FORCE_INLINE VecU32V V4ConvertToU32VSaturate(const Vec4V in, PxU32 power)
3595{
3596 PX_ASSERT(power == 0 && "Non-zero power not supported in convertToU32VSaturate");
3597 PX_UNUSED(power); // prevent warning in release builds
3598
3599 return vcvtq_u32_f32(in);
3600}
3601
3602PX_FORCE_INLINE void QuatGetMat33V(const QuatVArg q, Vec3V& column0, Vec3V& column1, Vec3V& column2)
3603{
3604 const FloatV one = FOne();
3605 const FloatV x = V4GetX(q);
3606 const FloatV y = V4GetY(q);
3607 const FloatV z = V4GetZ(q);
3608 const FloatV w = V4GetW(q);
3609
3610 const FloatV x2 = FAdd(x, x);
3611 const FloatV y2 = FAdd(y, y);
3612 const FloatV z2 = FAdd(z, z);
3613
3614 const FloatV xx = FMul(x2, x);
3615 const FloatV yy = FMul(y2, y);
3616 const FloatV zz = FMul(z2, z);
3617
3618 const FloatV xy = FMul(x2, y);
3619 const FloatV xz = FMul(x2, z);
3620 const FloatV xw = FMul(x2, w);
3621
3622 const FloatV yz = FMul(y2, z);
3623 const FloatV yw = FMul(y2, w);
3624 const FloatV zw = FMul(z2, w);
3625
3626 const FloatV v = FSub(one, xx);
3627
3628 column0 = V3Merge(FSub(FSub(one, yy), zz), FAdd(xy, zw), FSub(xz, yw));
3629 column1 = V3Merge(FSub(xy, zw), FSub(v, zz), FAdd(yz, xw));
3630 column2 = V3Merge(FAdd(xz, yw), FSub(yz, xw), FSub(v, yy));
3631}
3632
3633} // namespace aos
3634} // namespace physx
3635
3636#endif // PXFOUNDATION_PXUNIXNEONINLINEAOS_H
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_ALIGN(alignment, decl)
Definition PxPreprocessor.h:402
GLM_FUNC_DECL GLM_CONSTEXPR genType zero()
Definition constants.inl:6
uint64 uint64_t
Definition fwd.hpp:145
float float32_t
Definition fwd.hpp:162
uint32 uint32_t
Definition fwd.hpp:131
int32 int32_t
Definition fwd.hpp:71
uint16 uint16_t
Definition fwd.hpp:117
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxIsFinite(float f)
returns true if the passed number is a finite floating point number as opposed to INF,...
Definition PxMath.h:326