@@ -65,10 +65,20 @@ template<typename T NBL_STRUCT_CONSTRAINABLE>
65
65
struct acos_helper;
66
66
template<typename T NBL_STRUCT_CONSTRAINABLE>
67
67
struct sqrt_helper;
68
- template<typename T, typename U NBL_STRUCT_CONSTRAINABLE>
69
- struct mix_helper;
70
68
template<typename T NBL_STRUCT_CONSTRAINABLE>
71
69
struct modf_helper;
70
+ template<typename T NBL_STRUCT_CONSTRAINABLE>
71
+ struct round_helper;
72
+ template<typename T NBL_STRUCT_CONSTRAINABLE>
73
+ struct roundEven_helper;
74
+ template<typename T NBL_STRUCT_CONSTRAINABLE>
75
+ struct trunc_helper;
76
+ template<typename T NBL_STRUCT_CONSTRAINABLE>
77
+ struct ceil_helper;
78
+ template<typename T NBL_STRUCT_CONSTRAINABLE>
79
+ struct fma_helper;
80
+ template<typename T, typename U NBL_STRUCT_CONSTRAINABLE>
81
+ struct ldexp_helper;
72
82
73
83
#ifdef __HLSL_VERSION
74
84
@@ -104,6 +114,11 @@ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(log2_helper, log2, T)
104
114
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp2_helper, exp2, T)
105
115
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp_helper, exp, T)
106
116
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (floor_helper, floor, T)
117
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (round_helper, round, T)
118
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (roundEven_helper, roundEven, T)
119
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (trunc_helper, trunc, T)
120
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (ceil_helper, ceil, T)
121
+
107
122
#define ISINF_AND_ISNAN_RETURN_TYPE conditional_t<is_vector_v<T>, vector <bool , vector_traits<T>::Dimension>, bool >
108
123
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (isinf_helper, isInf, ISINF_AND_ISNAN_RETURN_TYPE)
109
124
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (isnan_helper, isNan, ISINF_AND_ISNAN_RETURN_TYPE)
@@ -120,16 +135,6 @@ struct pow_helper<T NBL_PARTIAL_REQ_BOT(always_true<decltype(spirv::pow<T>(exper
120
135
}
121
136
};
122
137
123
- template<typename T, typename U> NBL_PARTIAL_REQ_TOP (always_true<decltype (spirv::fMix<T>(experimental::declval<T>(), experimental::declval<T>(), experimental::declval<U>()))>)
124
- struct mix_helper<T, U NBL_PARTIAL_REQ_BOT (always_true<decltype (spirv::fMix<T>(experimental::declval<T>(), experimental::declval<T>(), experimental::declval<U>()))>) >
125
- {
126
- using return_t = conditional_t<is_vector_v<T>, vector <typename vector_traits<T>::scalar_type, vector_traits<T>::Dimension>, T>;
127
- static inline return_t __call (const T x, const T y, const U a)
128
- {
129
- return spirv::fMix<T>(x, y, a);
130
- }
131
- };
132
-
133
138
template<typename T> NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<T>)
134
139
struct modf_helper<T NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<T>) >
135
140
{
@@ -186,6 +191,26 @@ struct erf_helper<FloatingPoint NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScala
186
191
}
187
192
};
188
193
194
+ template<typename T> NBL_PARTIAL_REQ_TOP (always_true<decltype (spirv::fma<T>(experimental::declval<T>(), experimental::declval<T>(), experimental::declval<T>()))>)
195
+ struct fma_helper<T NBL_PARTIAL_REQ_BOT (always_true<decltype (spirv::fma<T>(experimental::declval<T>(), experimental::declval<T>(), experimental::declval<T>()))>) >
196
+ {
197
+ using return_t = T;
198
+ static inline return_t __call (const T x, const T y, const T z)
199
+ {
200
+ return spirv::fma<T>(x, y, z);
201
+ }
202
+ };
203
+
204
+ template<typename T, typename U> NBL_PARTIAL_REQ_TOP (always_true<decltype (spirv::ldexp<T>(experimental::declval<T>(), experimental::declval<U>()))>)
205
+ struct ldexp_helper<T, U NBL_PARTIAL_REQ_BOT (always_true<decltype (spirv::ldexp<T>(experimental::declval<T>(), experimental::declval<U>()))>) >
206
+ {
207
+ using return_t = T;
208
+ static inline return_t __call (const T arg, const U exp)
209
+ {
210
+ return spirv::ldexp<T, U>(arg, exp);
211
+ }
212
+ };
213
+
189
214
#else // C++ only specializations
190
215
191
216
@@ -212,6 +237,11 @@ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(log2_helper, concepts::FloatingPointScalar<T
212
237
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp2_helper, concepts::Scalar<T>, exp2, T)
213
238
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp_helper, concepts::Scalar<T>, exp, T)
214
239
AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (floor_helper, concepts::FloatingPointScalar<T>, floor, T)
240
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (round_helper, concepts::FloatingPointScalar<T>, round, T)
241
+ // TODO: uncomment when C++23
242
+ //AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(roundEven_helper, concepts::FloatingPointScalar<T>, roundeven, T)
243
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (trunc_helper, concepts::FloatingPointScalar<T>, trunc, T)
244
+ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (ceil_helper, concepts::FloatingPointScalar<T>, ceil, T)
215
245
#undef AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER
216
246
217
247
template<typename T>
@@ -265,24 +295,54 @@ struct isnan_helper<T>
265
295
}
266
296
};
267
297
268
- template<typename T, typename U >
269
- requires concepts::FloatingPoint<T> && (concepts::FloatingPoint<T> || concepts::Boolean<T >)
270
- struct mix_helper<T, U >
298
+ template<typename FloatingPoint >
299
+ NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<FloatingPoint >)
300
+ struct erf_helper<FloatingPoint NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<FloatingPoint>) >
271
301
{
272
- using return_t = T;
273
- static inline return_t __call (const T x, const T y, const U a)
274
- {
275
- return glm::mix (x, y ,a);
302
+ static FloatingPoint __call (NBL_CONST_REF_ARG (FloatingPoint) x)
303
+ {
304
+ return std::erf<FloatingPoint>(x);
276
305
}
277
306
};
278
307
308
+ // TODO: remove when C++23
279
309
template<typename FloatingPoint>
280
310
NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<FloatingPoint>)
281
- struct erf_helper <FloatingPoint NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<FloatingPoint>) >
311
+ struct roundEven_helper <FloatingPoint NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<FloatingPoint>) >
282
312
{
283
313
static FloatingPoint __call (NBL_CONST_REF_ARG (FloatingPoint) x)
284
314
{
285
- return std::erf<FloatingPoint>(x);
315
+ // TODO: no way this is optimal, find a better implementation
316
+ float tmp;
317
+ if (std::abs (std::modf (x, &tmp)) == 0.5f )
318
+ {
319
+ int32_t result = static_cast<int32_t>(x);
320
+ if (result % 2 != 0 )
321
+ result >= 0 ? ++result : --result;
322
+ return result;
323
+ }
324
+
325
+ return std::round (x);
326
+ }
327
+ };
328
+
329
+ template<typename FloatingPoint>
330
+ NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<FloatingPoint>)
331
+ struct fma_helper<FloatingPoint NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<FloatingPoint>) >
332
+ {
333
+ static FloatingPoint __call (NBL_CONST_REF_ARG (FloatingPoint) x, NBL_CONST_REF_ARG (FloatingPoint) y, NBL_CONST_REF_ARG (FloatingPoint) z)
334
+ {
335
+ return std::fma (x, y, z);
336
+ }
337
+ };
338
+
339
+ template<typename T, typename U>
340
+ NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<T> && concepts::IntegralScalar<U>)
341
+ struct ldexp_helper<T, U NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<T> && concepts::IntegralScalar<U>) >
342
+ {
343
+ static T __call (NBL_CONST_REF_ARG (T) arg, NBL_CONST_REF_ARG (U) exp)
344
+ {
345
+ return std::ldexp (arg, exp);
286
346
}
287
347
};
288
348
@@ -372,6 +432,10 @@ AUTO_SPECIALIZE_HELPER_FOR_VECTOR(cos_helper, T)
372
432
AUTO_SPECIALIZE_HELPER_FOR_VECTOR (sin_helper, T)
373
433
AUTO_SPECIALIZE_HELPER_FOR_VECTOR (acos_helper, T)
374
434
AUTO_SPECIALIZE_HELPER_FOR_VECTOR (modf_helper, T)
435
+ AUTO_SPECIALIZE_HELPER_FOR_VECTOR (round_helper, T)
436
+ AUTO_SPECIALIZE_HELPER_FOR_VECTOR (roundEven_helper, T)
437
+ AUTO_SPECIALIZE_HELPER_FOR_VECTOR (trunc_helper, T)
438
+ AUTO_SPECIALIZE_HELPER_FOR_VECTOR (ceil_helper, T)
375
439
376
440
#undef INT_VECTOR_RETURN_TYPE
377
441
#undef AUTO_SPECIALIZE_HELPER_FOR_VECTOR
@@ -394,6 +458,47 @@ struct pow_helper<T NBL_PARTIAL_REQ_BOT(VECTOR_SPECIALIZATION_CONCEPT) >
394
458
return output;
395
459
}
396
460
};
461
+
462
+ template<typename T>
463
+ NBL_PARTIAL_REQ_TOP (VECTOR_SPECIALIZATION_CONCEPT)
464
+ struct fma_helper<T NBL_PARTIAL_REQ_BOT (VECTOR_SPECIALIZATION_CONCEPT) >
465
+ {
466
+ using return_t = T;
467
+ static return_t __call (NBL_CONST_REF_ARG (T) x, NBL_CONST_REF_ARG (T) y, NBL_CONST_REF_ARG (T) z)
468
+ {
469
+ using traits = hlsl::vector_traits<T>;
470
+ array_get<T, typename traits::scalar_type> getter;
471
+ array_set<T, typename traits::scalar_type> setter;
472
+
473
+ return_t output;
474
+ for (uint32_t i = 0 ; i < traits::Dimension; ++i)
475
+ setter (output, i, fma_helper<typename traits::scalar_type>::__call (getter (x, i), getter (y, i), getter (z, i)));
476
+
477
+ return output;
478
+ }
479
+ };
480
+
481
+ template<typename T, typename U>
482
+ NBL_PARTIAL_REQ_TOP (VECTOR_SPECIALIZATION_CONCEPT && (vector_traits<T>::Dimension == vector_traits<U>::Dimension))
483
+ struct ldexp_helper<T, U NBL_PARTIAL_REQ_BOT (VECTOR_SPECIALIZATION_CONCEPT && (vector_traits<T>::Dimension == vector_traits<U>::Dimension)) >
484
+ {
485
+ using return_t = T;
486
+ static return_t __call (NBL_CONST_REF_ARG (T) arg, NBL_CONST_REF_ARG (U) exp)
487
+ {
488
+ using arg_traits = hlsl::vector_traits<T>;
489
+ using exp_traits = hlsl::vector_traits<U>;
490
+ array_get<T, typename arg_traits::scalar_type> argGetter;
491
+ array_get<U, typename exp_traits::scalar_type> expGetter;
492
+ array_set<T, typename arg_traits::scalar_type> setter;
493
+
494
+ return_t output;
495
+ for (uint32_t i = 0 ; i < arg_traits::Dimension; ++i)
496
+ setter (output, i, ldexp_helper<typename arg_traits::scalar_type, typename exp_traits::scalar_type>::__call (argGetter (arg, i), expGetter (exp, i)));
497
+
498
+ return output;
499
+ }
500
+ };
501
+
397
502
#undef VECTOR_SPECIALIZATION_CONCEPT
398
503
399
504
}
0 commit comments