16.6 KB、616行 生 Blame 履歴
1/// @ref core
2/// @file glm/detail/func_common_simd.inl
3
4#if GLM_ARCH & GLM_ARCH_SSE2_BIT
5
6#include "../simd/common.h"
7
8#include <immintrin.h>
9
10namespace glm{
11namespace detail
12{
13 template<qualifier Q>
14 struct compute_abs_vector<4, float, Q, true>
15 {
16 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)
17 {
18 vec<4, float, Q> result;
19 result.data = glm_vec4_abs(v.data);
20 return result;
21 }
22 };
23
24 template<qualifier Q>
25 struct compute_abs_vector<4, int, Q, true>
26 {
27 GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v)
28 {
29 vec<4, int, Q> result;
30 result.data = glm_ivec4_abs(v.data);
31 return result;
32 }
33 };
34
35 template<qualifier Q>
36 struct compute_floor<4, float, Q, true>
37 {
38 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)
39 {
40 vec<4, float, Q> result;
41 result.data = glm_vec4_floor(v.data);
42 return result;
43 }
44 };
45
46 template<qualifier Q>
47 struct compute_ceil<4, float, Q, true>
48 {
49 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)
50 {
51 vec<4, float, Q> result;
52 result.data = glm_vec4_ceil(v.data);
53 return result;
54 }
55 };
56
57 template<qualifier Q>
58 struct compute_fract<4, float, Q, true>
59 {
60 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)
61 {
62 vec<4, float, Q> result;
63 result.data = glm_vec4_fract(v.data);
64 return result;
65 }
66 };
67
68 template<qualifier Q>
69 struct compute_round<4, float, Q, true>
70 {
71 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)
72 {
73 vec<4, float, Q> result;
74 result.data = glm_vec4_round(v.data);
75 return result;
76 }
77 };
78
79 template<qualifier Q>
80 struct compute_mod<4, float, Q, true>
81 {
82 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y)
83 {
84 vec<4, float, Q> result;
85 result.data = glm_vec4_mod(x.data, y.data);
86 return result;
87 }
88 };
89
90 template<qualifier Q>
91 struct compute_min_vector<4, float, Q, true>
92 {
93 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)
94 {
95 vec<4, float, Q> result;
96 result.data = _mm_min_ps(v1.data, v2.data);
97 return result;
98 }
99 };
100
101 template<qualifier Q>
102 struct compute_min_vector<4, int, Q, true>
103 {
104 GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)
105 {
106 vec<4, int, Q> result;
107 result.data = _mm_min_epi32(v1.data, v2.data);
108 return result;
109 }
110 };
111
112 template<qualifier Q>
113 struct compute_min_vector<4, uint, Q, true>
114 {
115 GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)
116 {
117 vec<4, uint, Q> result;
118 result.data = _mm_min_epu32(v1.data, v2.data);
119 return result;
120 }
121 };
122
123 template<qualifier Q>
124 struct compute_max_vector<4, float, Q, true>
125 {
126 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)
127 {
128 vec<4, float, Q> result;
129 result.data = _mm_max_ps(v1.data, v2.data);
130 return result;
131 }
132 };
133
134 template<qualifier Q>
135 struct compute_max_vector<4, int, Q, true>
136 {
137 GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)
138 {
139 vec<4, int, Q> result;
140 result.data = _mm_max_epi32(v1.data, v2.data);
141 return result;
142 }
143 };
144
145 template<qualifier Q>
146 struct compute_max_vector<4, uint, Q, true>
147 {
148 GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)
149 {
150 vec<4, uint, Q> result;
151 result.data = _mm_max_epu32(v1.data, v2.data);
152 return result;
153 }
154 };
155
156 template<qualifier Q>
157 struct compute_clamp_vector<4, float, Q, true>
158 {
159 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal)
160 {
161 vec<4, float, Q> result;
162 result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data);
163 return result;
164 }
165 };
166
167 template<qualifier Q>
168 struct compute_clamp_vector<4, int, Q, true>
169 {
170 GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal)
171 {
172 vec<4, int, Q> result;
173 result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data);
174 return result;
175 }
176 };
177
178 template<qualifier Q>
179 struct compute_clamp_vector<4, uint, Q, true>
180 {
181 GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal)
182 {
183 vec<4, uint, Q> result;
184 result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data);
185 return result;
186 }
187 };
188
189 template<qualifier Q>
190 struct compute_mix_vector<4, float, bool, Q, true>
191 {
192 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a)
193 {
194 __m128i const Load = _mm_set_epi32(-static_cast<int>(a.w), -static_cast<int>(a.z), -static_cast<int>(a.y), -static_cast<int>(a.x));
195 __m128 const Mask = _mm_castsi128_ps(Load);
196
197 vec<4, float, Q> Result;
198# if 0 && GLM_ARCH & GLM_ARCH_AVX
199 Result.data = _mm_blendv_ps(x.data, y.data, Mask);
200# else
201 Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data));
202# endif
203 return Result;
204 }
205 };
206/* FIXME
207 template<qualifier Q>
208 struct compute_step_vector<float, Q, tvec4>
209 {
210 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x)
211 {
212 vec<4, float, Q> Result;
213 result.data = glm_vec4_step(edge.data, x.data);
214 return result;
215 }
216 };
217*/
218 template<qualifier Q>
219 struct compute_smoothstep_vector<4, float, Q, true>
220 {
221 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x)
222 {
223 vec<4, float, Q> Result;
224 Result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data);
225 return Result;
226 }
227 };
228
229 template<qualifier Q>
230 struct compute_fma<4, float, Q, true>
231 {
232 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b, vec<4, float, Q> const& c)
233 {
234 vec<4, float, Q> Result;
235 Result.data = glm_vec4_fma(a.data, b.data, c.data);
236 return Result;
237 }
238 };
239
240 template<qualifier Q>
241 struct compute_fma<3, float, Q, true>
242 {
243 GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b, vec<3, float, Q> const& c)
244 {
245 vec<3, float, Q> Result;
246 Result.data = glm_vec4_fma(a.data, b.data, c.data);
247 return Result;
248 }
249 };
250
251
252 template<qualifier Q>
253 struct compute_fma<4, double, Q, true>
254 {
255 GLM_FUNC_QUALIFIER static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b, vec<4, double, Q> const& c)
256 {
257 vec<4, double, Q> Result;
258# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG)
259 Result.data = _mm256_fmadd_pd(a.data, b.data, c.data);
260# elif (GLM_ARCH & GLM_ARCH_AVX_BIT)
261 Result.data = _mm256_add_pd(_mm256_mul_pd(a.data, b.data), c.data);
262# else
263 Result.data.setv(0, _mm_add_pd(_mm_mul_pd(a.data.getv(0), b.data.getv(0)), c.data.getv(0)));
264 Result.data.setv(1, _mm_add_pd(_mm_mul_pd(a.data.getv(1), b.data.getv(1)), c.data.getv(1)));
265# endif
266 return Result;
267 }
268 };
269
270 // copy vec3 to vec4 and set w to 0
271 template<qualifier Q>
272 struct convert_vec3_to_vec4W0<float, Q, true>
273 {
274 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
275 {
276 vec<4, float, Q> v;
277#if (GLM_ARCH & GLM_ARCH_SSE41_BIT)
278 v.data = _mm_blend_ps(a.data, _mm_setzero_ps(), 8);
279#else
280 __m128i mask = _mm_set_epi32(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
281 __m128 v0 = _mm_castsi128_ps(_mm_and_si128(_mm_castps_si128(a.data), mask));
282 v.data = v0;
283#endif
284 return v;
285 }
286 };
287
288 // copy vec3 to vec4 and set w to 1
289 template<qualifier Q>
290 struct convert_vec3_to_vec4W1<float, Q, true>
291 {
292 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
293 {
294 vec<4, float, Q> v;
295#if (GLM_ARCH & GLM_ARCH_SSE41_BIT)
296 v.data = _mm_blend_ps(a.data, _mm_set1_ps(1.0f), 8);
297#else
298 __m128 t1 = _mm_shuffle_ps(a.data, a.data, _MM_SHUFFLE(0, 2, 1, 3)); //permute x, w
299 __m128 t2 = _mm_move_ss(t1, _mm_set_ss(1.0f)); // set x to 1.0f
300 v.data = _mm_shuffle_ps(t2, t2, _MM_SHUFFLE(0, 2, 1, 3)); //permute x, w
301#endif
302 return v;
303 }
304 };
305
306 // copy vec3 to vec4 and set w to vec3.z
307 template<qualifier Q>
308 struct convert_vec3_to_vec4WZ<float, Q, true>
309 {
310 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
311 {
312 vec<4, float, Q> v;
313 v.data = _mm_shuffle_ps(a.data, a.data, _MM_SHUFFLE(2, 2, 1, 0));
314 return v;
315 }
316 };
317
318 // copy vec3 to vec4 and set w to 0
319 template<qualifier Q>
320 struct convert_vec3_to_vec4W0<double, Q, true>
321 {
322 GLM_FUNC_QUALIFIER static vec<4, double, Q> call(vec<3, double, Q> const& a)
323 {
324 vec<4, double, Q> v;
325#if (GLM_ARCH & GLM_ARCH_AVX_BIT)
326 v.data = _mm256_blend_pd(a.data, _mm256_setzero_pd(), 8);
327#else
328 v.data.setv(0, a.data.getv(0));
329 glm_dvec2 av2 = a.data.getv(1);
330 av2 = _mm_shuffle_pd(av2, _mm_setzero_pd(), 2);
331 v.data.setv(1, av2);
332#endif
333 return v;
334 }
335 };
336
337 // copy vec3 to vec4 and set w to vec3.z
338 template<qualifier Q>
339 struct convert_vec3_to_vec4WZ<double, Q, true>
340 {
341 GLM_FUNC_QUALIFIER static vec<4, double, Q> call(vec<3, double, Q> const& a)
342 {
343 vec<4, double, Q> v;
344#if (GLM_ARCH & GLM_ARCH_AVX_BIT)
345 v.data = _mm256_permute_pd(a.data, 2);
346#else
347 v.data.setv(0, a.data.getv(0));
348 glm_dvec2 av2 = a.data.getv(1);
349 __m128d t1 = _mm_shuffle_pd(av2, av2, 0);
350 v.data.setv(1, t1);
351#endif
352 return v;
353 }
354 };
355
356 // copy vec3 to vec4 and set w to 1
357 template<qualifier Q>
358 struct convert_vec3_to_vec4W1<double, Q, true>
359 {
360 GLM_FUNC_QUALIFIER static vec<4, double, Q> call(vec<3, double, Q> const& a)
361 {
362 vec<4, double, Q> v;
363#if (GLM_ARCH & GLM_ARCH_AVX_BIT)
364 v.data = _mm256_blend_pd(a.data, _mm256_set1_pd(1.0), 8);
365#else
366 v.data.setv(0, a.data.getv(0));
367 glm_dvec2 av2 = a.data.getv(1);
368 av2 = _mm_shuffle_pd(av2, _mm_set1_pd(1.), 2);
369 v.data.setv(1, av2);
370#endif
371 return v;
372 }
373 };
374
375 template<qualifier Q>
376 struct convert_vec4_to_vec3<float, Q, true> {
377 GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<4, float, Q> const& a)
378 {
379 vec<3, float, Q> v;
380 v.data = a.data;
381 return v;
382 }
383 };
384
385 template<qualifier Q>
386 struct convert_vec4_to_vec3<double, Q, true> {
387 GLM_FUNC_QUALIFIER static vec<3, double, Q> call(vec<4, double, Q> const& a)
388 {
389 vec<3, double, Q> v;
390#if GLM_ARCH & GLM_ARCH_AVX_BIT
391 v.data = a.data;
392#else
393 v.data.setv(0, a.data.getv(0));
394 v.data.setv(1, a.data.getv(1));
395#endif
396 return v;
397 }
398 };
399
400
401 // set all coordinates to same value vec[c]
402 template<length_t L, qualifier Q>
403 struct convert_splat<L, float, Q, true> {
404 template<int c>
405 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, float, Q> call(vec<L, float, Q> const& a)
406 {
407 vec<L, float, Q> Result;
408 const int s = _MM_SHUFFLE(c, c, c, c);
409 glm_f32vec4 va = static_cast<glm_f32vec4>(a.data);
410# if GLM_ARCH & GLM_ARCH_AVX_BIT
411 Result.data = _mm_permute_ps(va, s);
412# else
413 Result.data = _mm_shuffle_ps(va, va, s);
414# endif
415 return Result;
416 }
417 };
418
419 // set all coordinates to same value vec[c]
420 template<length_t L, qualifier Q>
421 struct convert_splat<L, double, Q, true> {
422
423 template<bool, int c>
424 struct detailSSE
425 {};
426
427 template<int c>
428 struct detailSSE<true, c>
429 {
430 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
431 {
432 vec<L, double, Q> Result;
433 glm_f64vec2 r0 = _mm_shuffle_pd(a.data.getv(0), a.data.getv(0), c | c << 1);
434 Result.data.setv(0, r0);
435 Result.data.setv(1, r0);
436 return Result;
437 }
438 };
439
440 template<int c>
441 struct detailSSE<false, c>
442 {
443 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
444 {
445 vec<L, double, Q> Result;
446 const unsigned int d = static_cast<unsigned int>(c - 2);
447 glm_f64vec2 r0 = _mm_shuffle_pd(a.data.getv(1), a.data.getv(1), d | d << 1);
448 Result.data.setv(0, r0);
449 Result.data.setv(1, r0);
450 return Result;
451 }
452 };
453
454#if GLM_ARCH & GLM_ARCH_AVX_BIT
455 template<bool, int c> //note: bool is useless but needed to compil on linux (gcc)
456 struct detailAVX
457 {};
458
459 template<bool b>
460 struct detailAVX<b, 0>
461 {
462 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
463 {
464 vec<L, double, Q> Result;
465 __m256d t1 = _mm256_permute2f128_pd(a.data, a.data, 0x0);
466 Result.data = _mm256_permute_pd(t1, 0);
467 return Result;
468 }
469 };
470
471 template<bool b>
472 struct detailAVX<b, 1>
473 {
474 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
475 {
476 vec<L, double, Q> Result;
477 __m256d t1 = _mm256_permute2f128_pd(a.data, a.data, 0x0);
478 Result.data = _mm256_permute_pd(t1, 0xf);
479 return Result;
480 }
481 };
482
483 template<bool b>
484 struct detailAVX<b, 2>
485 {
486 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
487 {
488 vec<L, double, Q> Result;
489 __m256d t2 = _mm256_permute2f128_pd(a.data, a.data, 0x11);
490 Result.data = _mm256_permute_pd(t2, 0x0);
491 return Result;
492 }
493 };
494
495 template<bool b>
496 struct detailAVX<b, 3>
497 {
498 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
499 {
500 vec<L, double, Q> Result;
501 __m256d t2 = _mm256_permute2f128_pd(a.data, a.data, 0x11);
502 Result.data = _mm256_permute_pd(t2, 0xf);
503 return Result;
504 }
505 };
506#endif //GLM_ARCH & GLM_ARCH_AVX_BIT
507
508 template<int c>
509 GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, double, Q> call(vec<L, double, Q> const& a)
510 {
511 //return compute_splat<L, double, Q, false>::call<c>(a);
512 vec<L, double, Q> Result;
513# if GLM_ARCH & GLM_ARCH_AVX2_BIT
514 Result.data = _mm256_permute4x64_pd(a.data, _MM_SHUFFLE(c, c, c, c));
515# elif GLM_ARCH & GLM_ARCH_AVX_BIT
516 Result = detailAVX<true, c>::call(a);
517# else
518#if 1 //detail<(c <= 1), c>::call2(a) is equivalent to following code but without if constexpr usage
519 Result = detailSSE<(c <= 1), c>::call(a);
520#else
521 if constexpr (c <= 1)
522 {
523 glm_f64vec2 r0 = _mm_shuffle_pd(a.data.getv(0), a.data.getv(0), c | c << 1);
524 Result.data.setv(0, r0);
525 Result.data.setv(1, r0);
526 }
527 else
528 {
529 const unsigned int d = (unsigned int)(c - 2);
530 glm_f64vec2 r0 = _mm_shuffle_pd(a.data.getv(1), a.data.getv(1), d | d << 1);
531 Result.data.setv(0, r0);
532 Result.data.setv(1, r0);
533 }
534#endif
535# endif
536 return Result;
537 }
538 };
539
540
541}//namespace detail
542}//namespace glm
543
544#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
545
546#if GLM_ARCH & GLM_ARCH_NEON_BIT
547namespace glm {
548namespace detail {
549/* FIXME: Breaking Windows ARM Github C.I.
550 template<qualifier Q>
551 struct convert_vec3_to_vec4W0<float, Q, true>
552 {
553 GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<3, float, Q> const& a)
554 {
555 vec<4, float, Q> v;
556 static const uint32x4_t mask = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0 };
557 v.data = vbslq_f32(mask, a.data, vdupq_n_f32(0));
558 return v;
559 }
560 };
561*/
562 template<qualifier Q>
563 struct convert_vec4_to_vec3<float, Q, true> {
564 GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<4, float, Q> const& a)
565 {
566 vec<3, float, Q> v;
567 v.data = a.data;
568 return v;
569 }
570 };
571
572/* compute_splat is never called?
573 template<length_t L, qualifier Q>
574 struct compute_splat<L, float, Q, true> {
575 template<int c>
576 GLM_FUNC_QUALIFIER static vec<L, float, Q> call(vec<L, float, Q> const& a)
577 {
578 (void)a;
579 }
580
581 template<>
582 GLM_FUNC_QUALIFIER static vec<L, float, Q> call<0>(vec<L, float, Q> const& a)
583 {
584 vec<L, float, Q> Result;
585 Result.data = vdupq_lane_f32(vget_low_f32(a.data), 0);
586 return Result;
587 }
588
589 template<>
590 GLM_FUNC_QUALIFIER static vec<L, float, Q> call<1>(vec<L, float, Q> const& a)
591 {
592 vec<L, float, Q> Result;
593 Result.data = vdupq_lane_f32(vget_low_f32(a.data), 1);
594 return Result;
595 }
596
597 template<>
598 GLM_FUNC_QUALIFIER static vec<L, float, Q> call<2>(vec<L, float, Q> const& a)
599 {
600 vec<L, float, Q> Result;
601 Result.data = vdupq_lane_f32(vget_high_f32(a.data), 0);
602 return Result;
603 }
604
605 template<>
606 GLM_FUNC_QUALIFIER static vec<L, float, Q> call<3>(vec<L, float, Q> const& a)
607 {
608 vec<L, float, Q> Result;
609 Result.data = vdupq_lane_f32(vget_high_f32(a.data), 1);
610 return Result;
611 }
612 };
613*/
614}//namespace detail
615}//namespace glm
616#endif //GLM_ARCH & GLM_ARCH_NEON_BIT