ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / util / util_math_float4.h
1 /*
2  * Copyright 2011-2017 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __UTIL_MATH_FLOAT4_H__
18 #define __UTIL_MATH_FLOAT4_H__
19
20 #ifndef __UTIL_MATH_H__
21 #  error "Do not include this file directly, include util_types.h instead."
22 #endif
23
24 CCL_NAMESPACE_BEGIN
25
26 /*******************************************************************************
27  * Declaration.
28  */
29
30 #ifndef __KERNEL_OPENCL__
31 ccl_device_inline float4 operator-(const float4 &a);
32 ccl_device_inline float4 operator*(const float4 &a, const float4 &b);
33 ccl_device_inline float4 operator*(const float4 &a, float f);
34 ccl_device_inline float4 operator*(float f, const float4 &a);
35 ccl_device_inline float4 operator/(const float4 &a, float f);
36 ccl_device_inline float4 operator/(const float4 &a, const float4 &b);
37 ccl_device_inline float4 operator+(const float4 &a, const float4 &b);
38 ccl_device_inline float4 operator-(const float4 &a, const float4 &b);
39 ccl_device_inline float4 operator+=(float4 &a, const float4 &b);
40 ccl_device_inline float4 operator*=(float4 &a, const float4 &b);
41 ccl_device_inline float4 operator*=(float4 &a, float f);
42 ccl_device_inline float4 operator/=(float4 &a, float f);
43
44 ccl_device_inline int4 operator<(const float4 &a, const float4 &b);
45 ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
46 ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
47 ccl_device_inline bool operator==(const float4 &a, const float4 &b);
48
49 ccl_device_inline float dot(const float4 &a, const float4 &b);
50 ccl_device_inline float len_squared(const float4 &a);
51 ccl_device_inline float4 rcp(const float4 &a);
52 ccl_device_inline float4 sqrt(const float4 &a);
53 ccl_device_inline float4 sqr(const float4 &a);
54 ccl_device_inline float4 cross(const float4 &a, const float4 &b);
55 ccl_device_inline bool is_zero(const float4 &a);
56 ccl_device_inline float average(const float4 &a);
57 ccl_device_inline float len(const float4 &a);
58 ccl_device_inline float4 normalize(const float4 &a);
59 ccl_device_inline float4 safe_normalize(const float4 &a);
60 ccl_device_inline float4 min(const float4 &a, const float4 &b);
61 ccl_device_inline float4 max(const float4 &a, const float4 &b);
62 ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
63 ccl_device_inline float4 fabs(const float4 &a);
64 #endif /* !__KERNEL_OPENCL__*/
65
66 #ifdef __KERNEL_SSE__
67 template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
68 __forceinline const float4 shuffle(const float4 &b);
69 template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
70 __forceinline const float4 shuffle(const float4 &a, const float4 &b);
71
72 template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b);
73
74 template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b);
75 template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b);
76
77 #  ifdef __KERNEL_SSE3__
78 template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b);
79 template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b);
80 #  endif
81 #endif /* __KERNEL_SSE__ */
82
83 #ifndef __KERNEL_GPU__
84 ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b);
85 ccl_device_inline float4 reduce_min(const float4 &a);
86 ccl_device_inline float4 reduce_max(const float4 &a);
87 ccl_device_inline float4 reduce_add(const float4 &a);
88 #endif /* !__KERNEL_GPU__ */
89
90 /*******************************************************************************
91  * Definition.
92  */
93
94 #ifndef __KERNEL_OPENCL__
95 ccl_device_inline float4 operator-(const float4 &a)
96 {
97 #  ifdef __KERNEL_SSE__
98   __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
99   return float4(_mm_xor_ps(a.m128, mask));
100 #  else
101   return make_float4(-a.x, -a.y, -a.z, -a.w);
102 #  endif
103 }
104
105 ccl_device_inline float4 operator*(const float4 &a, const float4 &b)
106 {
107 #  ifdef __KERNEL_SSE__
108   return float4(_mm_mul_ps(a.m128, b.m128));
109 #  else
110   return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
111 #  endif
112 }
113
114 ccl_device_inline float4 operator*(const float4 &a, float f)
115 {
116 #  if defined(__KERNEL_SSE__)
117   return a * make_float4(f);
118 #  else
119   return make_float4(a.x * f, a.y * f, a.z * f, a.w * f);
120 #  endif
121 }
122
123 ccl_device_inline float4 operator*(float f, const float4 &a)
124 {
125   return a * f;
126 }
127
128 ccl_device_inline float4 operator/(const float4 &a, float f)
129 {
130   return a * (1.0f / f);
131 }
132
133 ccl_device_inline float4 operator/(const float4 &a, const float4 &b)
134 {
135 #  ifdef __KERNEL_SSE__
136   return float4(_mm_div_ps(a.m128, b.m128));
137 #  else
138   return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
139 #  endif
140 }
141
142 ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
143 {
144 #  ifdef __KERNEL_SSE__
145   return float4(_mm_add_ps(a.m128, b.m128));
146 #  else
147   return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
148 #  endif
149 }
150
151 ccl_device_inline float4 operator-(const float4 &a, const float4 &b)
152 {
153 #  ifdef __KERNEL_SSE__
154   return float4(_mm_sub_ps(a.m128, b.m128));
155 #  else
156   return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
157 #  endif
158 }
159
160 ccl_device_inline float4 operator+=(float4 &a, const float4 &b)
161 {
162   return a = a + b;
163 }
164
165 ccl_device_inline float4 operator*=(float4 &a, const float4 &b)
166 {
167   return a = a * b;
168 }
169
170 ccl_device_inline float4 operator*=(float4 &a, float f)
171 {
172   return a = a * f;
173 }
174
175 ccl_device_inline float4 operator/=(float4 &a, float f)
176 {
177   return a = a / f;
178 }
179
180 ccl_device_inline int4 operator<(const float4 &a, const float4 &b)
181 {
182 #  ifdef __KERNEL_SSE__
183   return int4(_mm_castps_si128(_mm_cmplt_ps(a.m128, b.m128)));
184 #  else
185   return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w);
186 #  endif
187 }
188
189 ccl_device_inline int4 operator>=(const float4 &a, const float4 &b)
190 {
191 #  ifdef __KERNEL_SSE__
192   return int4(_mm_castps_si128(_mm_cmpge_ps(a.m128, b.m128)));
193 #  else
194   return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w);
195 #  endif
196 }
197
198 ccl_device_inline int4 operator<=(const float4 &a, const float4 &b)
199 {
200 #  ifdef __KERNEL_SSE__
201   return int4(_mm_castps_si128(_mm_cmple_ps(a.m128, b.m128)));
202 #  else
203   return make_int4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w);
204 #  endif
205 }
206
207 ccl_device_inline bool operator==(const float4 &a, const float4 &b)
208 {
209 #  ifdef __KERNEL_SSE__
210   return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 15) == 15;
211 #  else
212   return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
213 #  endif
214 }
215
216 ccl_device_inline float dot(const float4 &a, const float4 &b)
217 {
218 #  if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
219   return _mm_cvtss_f32(_mm_dp_ps(a, b, 0xFF));
220 #  else
221   return (a.x * b.x + a.y * b.y) + (a.z * b.z + a.w * b.w);
222 #  endif
223 }
224
225 ccl_device_inline float len_squared(const float4 &a)
226 {
227   return dot(a, a);
228 }
229
230 ccl_device_inline float4 rcp(const float4 &a)
231 {
232 #  ifdef __KERNEL_SSE__
233   /* Don't use _mm_rcp_ps due to poor precision. */
234   return float4(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
235 #  else
236   return make_float4(1.0f / a.x, 1.0f / a.y, 1.0f / a.z, 1.0f / a.w);
237 #  endif
238 }
239
240 ccl_device_inline float4 sqrt(const float4 &a)
241 {
242 #  ifdef __KERNEL_SSE__
243   return float4(_mm_sqrt_ps(a.m128));
244 #  else
245   return make_float4(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z), sqrtf(a.w));
246 #  endif
247 }
248
249 ccl_device_inline float4 sqr(const float4 &a)
250 {
251   return a * a;
252 }
253
254 ccl_device_inline float4 cross(const float4 &a, const float4 &b)
255 {
256 #  ifdef __KERNEL_SSE__
257   return (shuffle<1, 2, 0, 0>(a) * shuffle<2, 0, 1, 0>(b)) -
258          (shuffle<2, 0, 1, 0>(a) * shuffle<1, 2, 0, 0>(b));
259 #  else
260   return make_float4(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, 0.0f);
261 #  endif
262 }
263
264 ccl_device_inline bool is_zero(const float4 &a)
265 {
266 #  ifdef __KERNEL_SSE__
267   return a == make_float4(0.0f);
268 #  else
269   return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
270 #  endif
271 }
272
273 ccl_device_inline float4 reduce_add(const float4 &a)
274 {
275 #  ifdef __KERNEL_SSE__
276 #    ifdef __KERNEL_SSE3__
277   float4 h(_mm_hadd_ps(a.m128, a.m128));
278   return float4(_mm_hadd_ps(h.m128, h.m128));
279 #    else
280   float4 h(shuffle<1, 0, 3, 2>(a) + a);
281   return shuffle<2, 3, 0, 1>(h) + h;
282 #    endif
283 #  else
284   float sum = (a.x + a.y) + (a.z + a.w);
285   return make_float4(sum, sum, sum, sum);
286 #  endif
287 }
288
289 ccl_device_inline float average(const float4 &a)
290 {
291   return reduce_add(a).x * 0.25f;
292 }
293
294 ccl_device_inline float len(const float4 &a)
295 {
296   return sqrtf(dot(a, a));
297 }
298
299 ccl_device_inline float4 normalize(const float4 &a)
300 {
301   return a / len(a);
302 }
303
304 ccl_device_inline float4 safe_normalize(const float4 &a)
305 {
306   float t = len(a);
307   return (t != 0.0f) ? a / t : a;
308 }
309
310 ccl_device_inline float4 min(const float4 &a, const float4 &b)
311 {
312 #  ifdef __KERNEL_SSE__
313   return float4(_mm_min_ps(a.m128, b.m128));
314 #  else
315   return make_float4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w));
316 #  endif
317 }
318
319 ccl_device_inline float4 max(const float4 &a, const float4 &b)
320 {
321 #  ifdef __KERNEL_SSE__
322   return float4(_mm_max_ps(a.m128, b.m128));
323 #  else
324   return make_float4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w));
325 #  endif
326 }
327
328 ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx)
329 {
330   return min(max(a, mn), mx);
331 }
332
333 ccl_device_inline float4 fabs(const float4 &a)
334 {
335 #  ifdef __KERNEL_SSE__
336   return float4(_mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))));
337 #  else
338   return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
339 #  endif
340 }
341 #endif /* !__KERNEL_OPENCL__*/
342
343 #ifdef __KERNEL_SSE__
344 template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
345 __forceinline const float4 shuffle(const float4 &b)
346 {
347   return float4(_mm_castsi128_ps(
348       _mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(index_3, index_2, index_1, index_0))));
349 }
350
351 template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
352 __forceinline const float4 shuffle(const float4 &a, const float4 &b)
353 {
354   return float4(_mm_shuffle_ps(a.m128, b.m128, _MM_SHUFFLE(index_3, index_2, index_1, index_0)));
355 }
356
357 template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &b)
358 {
359   return float4(_mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(b))));
360 }
361
362 template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4 &a, const float4 &b)
363 {
364   return float4(_mm_movelh_ps(a.m128, b.m128));
365 }
366
367 template<> __forceinline const float4 shuffle<2, 3, 2, 3>(const float4 &a, const float4 &b)
368 {
369   return float4(_mm_movehl_ps(b.m128, a.m128));
370 }
371
372 #  ifdef __KERNEL_SSE3__
373 template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4 &b)
374 {
375   return float4(_mm_moveldup_ps(b));
376 }
377
378 template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b)
379 {
380   return float4(_mm_movehdup_ps(b));
381 }
382 #  endif /* __KERNEL_SSE3__ */
383 #endif   /* __KERNEL_SSE__ */
384
385 #ifndef __KERNEL_GPU__
386 ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b)
387 {
388 #  ifdef __KERNEL_SSE__
389   return float4(_mm_blendv_ps(b.m128, a.m128, _mm_castsi128_ps(mask.m128)));
390 #  else
391   return make_float4(
392       (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w);
393 #  endif
394 }
395
396 ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
397 {
398   /* Replace elements of x with zero where mask isn't set. */
399   return select(mask, a, make_float4(0.0f));
400 }
401
402 ccl_device_inline float4 reduce_min(const float4 &a)
403 {
404 #  ifdef __KERNEL_SSE__
405   float4 h = min(shuffle<1, 0, 3, 2>(a), a);
406   return min(shuffle<2, 3, 0, 1>(h), h);
407 #  else
408   return make_float4(min(min(a.x, a.y), min(a.z, a.w)));
409 #  endif
410 }
411
412 ccl_device_inline float4 reduce_max(const float4 &a)
413 {
414 #  ifdef __KERNEL_SSE__
415   float4 h = max(shuffle<1, 0, 3, 2>(a), a);
416   return max(shuffle<2, 3, 0, 1>(h), h);
417 #  else
418   return make_float4(max(max(a.x, a.y), max(a.z, a.w)));
419 #  endif
420 }
421
422 ccl_device_inline float4 load_float4(const float *v)
423 {
424 #  ifdef __KERNEL_SSE__
425   return float4(_mm_loadu_ps(v));
426 #  else
427   return make_float4(v[0], v[1], v[2], v[3]);
428 #  endif
429 }
430
431 #endif /* !__KERNEL_GPU__ */
432
433 CCL_NAMESPACE_END
434
435 #endif /* __UTIL_MATH_FLOAT4_H__ */