@@ -65,10 +65,20 @@ template<typename T NBL_STRUCT_CONSTRAINABLE>
6565struct acos_helper;
6666template<typename T NBL_STRUCT_CONSTRAINABLE>
6767struct sqrt_helper;
68- template<typename T, typename U NBL_STRUCT_CONSTRAINABLE>
69- struct mix_helper;
7068template<typename T NBL_STRUCT_CONSTRAINABLE>
7169struct 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;
7282
7383#ifdef __HLSL_VERSION
7484
@@ -104,6 +114,11 @@ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(log2_helper, log2, T)
104114AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp2_helper, exp2, T)
105115AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp_helper, exp, T)
106116AUTO_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+
107122#define ISINF_AND_ISNAN_RETURN_TYPE conditional_t<is_vector_v<T>, vector <bool , vector_traits<T>::Dimension>, bool >
108123AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (isinf_helper, isInf, ISINF_AND_ISNAN_RETURN_TYPE)
109124AUTO_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
120135 }
121136};
122137
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-
133138template<typename T> NBL_PARTIAL_REQ_TOP (concepts::FloatingPointScalar<T>)
134139struct modf_helper<T NBL_PARTIAL_REQ_BOT (concepts::FloatingPointScalar<T>) >
135140{
@@ -186,6 +191,26 @@ struct erf_helper<FloatingPoint NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScala
186191 }
187192};
188193
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+
189214#else // C++ only specializations
190215
191216
@@ -212,6 +237,11 @@ AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(log2_helper, concepts::FloatingPointScalar<T
212237AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp2_helper, concepts::Scalar<T>, exp2, T)
213238AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER (exp_helper, concepts::Scalar<T>, exp, T)
214239AUTO_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)
215245#undef AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER
216246
217247template<typename T>
@@ -265,24 +295,54 @@ struct isnan_helper<T>
265295 }
266296};
267297
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>) >
271301{
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);
276305 }
277306};
278307
308+ // TODO: remove when C++23
279309template<typename FloatingPoint>
280310NBL_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>) >
282312{
283313 static FloatingPoint __call (NBL_CONST_REF_ARG (FloatingPoint) x)
284314 {
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);
286346 }
287347};
288348
@@ -372,6 +432,10 @@ AUTO_SPECIALIZE_HELPER_FOR_VECTOR(cos_helper, T)
372432AUTO_SPECIALIZE_HELPER_FOR_VECTOR (sin_helper, T)
373433AUTO_SPECIALIZE_HELPER_FOR_VECTOR (acos_helper, T)
374434AUTO_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)
375439
376440#undef INT_VECTOR_RETURN_TYPE
377441#undef AUTO_SPECIALIZE_HELPER_FOR_VECTOR
@@ -394,6 +458,47 @@ struct pow_helper<T NBL_PARTIAL_REQ_BOT(VECTOR_SPECIALIZATION_CONCEPT) >
394458 return output;
395459 }
396460};
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+
397502#undef VECTOR_SPECIALIZATION_CONCEPT
398503
399504}
0 commit comments