Skip to content

New morton class with arithmetic and comparison operators #860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cdcc9ad
Initial commit
Fletterio Mar 21, 2025
8e84558
Merge branch 'concepts_fix' into mortons
Fletterio Mar 21, 2025
d33fab5
Merge branch 'concepts_fix' into mortons
Fletterio Mar 21, 2025
5fe6c08
CHeckpoint before master merge
Fletterio Mar 23, 2025
f18b2fa
Checkpoint before merging new type_traits change
Fletterio Mar 24, 2025
7d86cba
Merge branch 'master' into mortons
Fletterio Mar 24, 2025
4ebc555
Works, but throws DXC warning
Fletterio Mar 24, 2025
55a2ef6
Added concept for valid morton dimensions
Fletterio Mar 24, 2025
f516256
Creation from vector working as intended
Fletterio Mar 25, 2025
534d81b
Added some extra macro specifiers, vector truncation with no warnings…
Fletterio Mar 26, 2025
6256390
Add safe copile-time vector truncation and some function specifiers f…
Fletterio Mar 26, 2025
246cefc
Morton class done!
Fletterio Mar 27, 2025
1c7f791
Remove some leftover commented code
Fletterio Mar 27, 2025
5088799
Remove leaking macro
Fletterio Mar 27, 2025
e25a35c
Bugfixes with arithmetic
Fletterio Mar 28, 2025
0d9dd4a
Checkpoint, have to check why vector compat isn't working
Fletterio Apr 1, 2025
89d2bf2
Refactor morton class, get new conversion running
Fletterio Apr 2, 2025
de4d0fb
Add new classes for encoding/decoding of mortn codes
Fletterio Apr 3, 2025
799420e
Fix conversion operators
Fletterio Apr 4, 2025
52323bc
Finish the rest of comparison ops and we're done!
Fletterio Apr 5, 2025
b6b7003
Final Mortons
Fletterio Apr 7, 2025
60ff99a
Clean up the emulated int code, fix some constant creation in the mor…
Fletterio Apr 8, 2025
5560162
Addressing latest PR review. Generic overloads for of different func…
Fletterio Apr 8, 2025
e50c56b
Bunch of emulated int64 fixes regarding creation, comparison operator…
Fletterio Apr 9, 2025
b1de9c3
Fix automatic specialize macro in cpp compat intrinsics, add intrins…
Fletterio Apr 9, 2025
ea8cd43
Checkpoint: adding a bunch of operators to emulated vector types
Fletterio Apr 11, 2025
53a5f6a
Vectorized encode/decode for better pipelining
Fletterio Apr 11, 2025
cf52d9c
Adress the last of PR review changes: vectorize more operators, add a…
Fletterio Apr 14, 2025
f954522
Removed `NBL_CONSTEXPR_INLINE_FUNC` macro, replaced all usages with
Fletterio Apr 24, 2025
2d0ffba
Fix the last of the operators
Fletterio Apr 28, 2025
68edc32
Change examples test submodule for master merge
Fletterio Apr 28, 2025
5013c89
Merged master
Fletterio Apr 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions include/nbl/builtin/hlsl/complex.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -427,22 +427,6 @@ complex_t<Scalar> rotateRight(NBL_CONST_REF_ARG(complex_t<Scalar>) value)
return retVal;
}

template<typename Scalar>
struct ternary_operator< complex_t<Scalar> >
{
using type_t = complex_t<Scalar>;

complex_t<Scalar> operator()(bool condition, NBL_CONST_REF_ARG(complex_t<Scalar>) lhs, NBL_CONST_REF_ARG(complex_t<Scalar>) rhs)
{
const vector<Scalar, 2> lhsVector = vector<Scalar, 2>(lhs.real(), lhs.imag());
const vector<Scalar, 2> rhsVector = vector<Scalar, 2>(rhs.real(), rhs.imag());
const vector<Scalar, 2> resultVector = condition ? lhsVector : rhsVector;
const complex_t<Scalar> result = { resultVector.x, resultVector.y };
return result;
}
};


}
}

Expand Down
10 changes: 10 additions & 0 deletions include/nbl/builtin/hlsl/concepts/core.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,22 @@ struct is_emulating_floating_point_scalar
{
NBL_CONSTEXPR_STATIC_INLINE bool value = FloatingPointScalar<T>;
};

template<typename T>
struct is_emulating_integral_scalar
{
NBL_CONSTEXPR_STATIC_INLINE bool value = IntegralScalar<T>;
};
}

//! Floating point types are native floating point types or types that imitate native floating point types (for example emulated_float64_t)
template<typename T>
NBL_BOOL_CONCEPT FloatingPointLikeScalar = impl::is_emulating_floating_point_scalar<T>::value;

//! Integral-like types are native integral types or types that imitate native integral types (for example emulated_uint64_t)
template<typename T>
NBL_BOOL_CONCEPT IntegralLikeScalar = impl::is_emulating_integral_scalar<T>::value;

}
}
}
Expand Down
2 changes: 2 additions & 0 deletions include/nbl/builtin/hlsl/concepts/vector.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ NBL_BOOL_CONCEPT FloatingPointLikeVectorial = concepts::Vectorial<T> && concepts
template<typename T>
NBL_BOOL_CONCEPT IntVectorial = concepts::Vectorial<T> && (is_integral_v<typename vector_traits<T>::scalar_type>);
template<typename T>
NBL_BOOL_CONCEPT IntegralLikeVectorial = concepts::Vectorial<T> && concepts::IntegralLikeScalar<typename vector_traits<T>::scalar_type>;
template<typename T>
NBL_BOOL_CONCEPT SignedIntVectorial = concepts::Vectorial<T> && concepts::SignedIntegralScalar<typename vector_traits<T>::scalar_type>;

}
Expand Down
3 changes: 3 additions & 0 deletions include/nbl/builtin/hlsl/cpp_compat.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
#include <nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl>
#include <nbl/builtin/hlsl/cpp_compat/promote.hlsl>

// Had to push some stuff here to avoid circular dependencies
#include <nbl/builtin/hlsl/cpp_compat/impl/vector_impl.hlsl>

#endif
86 changes: 56 additions & 30 deletions include/nbl/builtin/hlsl/cpp_compat/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,7 @@
#define _NBL_BUILTIN_HLSL_CPP_COMPAT_BASIC_INCLUDED_

#include <nbl/builtin/hlsl/macros.h>

namespace nbl
{
namespace hlsl
{
namespace impl
{
template<typename To, typename From, typename Enabled = void>
struct static_cast_helper
{
static inline To cast(From u)
{
#ifndef __HLSL_VERSION
return static_cast<To>(u);
#else
return To(u);
#endif
}
};
}

template<typename To, typename From>
inline To _static_cast(From v)
{
return impl::static_cast_helper<To, From>::cast(v);
}

}
}
#include <nbl/builtin/hlsl/concepts/impl/base.hlsl>

#ifndef __HLSL_VERSION
#include <type_traits>
Expand All @@ -39,10 +11,14 @@ inline To _static_cast(From v)
#define NBL_CONSTEXPR constexpr // TODO: rename to NBL_CONSTEXPR_VAR
#define NBL_CONSTEXPR_FUNC constexpr
#define NBL_CONSTEXPR_STATIC constexpr static
#define NBL_CONSTEXPR_INLINE constexpr inline
#define NBL_CONSTEXPR_STATIC_INLINE constexpr static inline
#define NBL_CONSTEXPR_STATIC_FUNC constexpr static
#define NBL_CONSTEXPR_INLINE_FUNC constexpr inline
#define NBL_CONSTEXPR_STATIC_INLINE_FUNC constexpr static inline
#define NBL_CONSTEXPR_FORCED_INLINE_FUNC NBL_FORCE_INLINE constexpr
#define NBL_CONST_MEMBER_FUNC const
#define NBL_IF_CONSTEXPR(...) if constexpr (__VA_ARGS__)

namespace nbl::hlsl
{
Expand All @@ -65,14 +41,19 @@ namespace nbl::hlsl

#else


#define ARROW .arrow().
#define NBL_CONSTEXPR const static // TODO: rename to NBL_CONSTEXPR_VAR
#define NBL_CONSTEXPR_FUNC
#define NBL_CONSTEXPR_STATIC const static
#define NBL_CONSTEXPR_INLINE const static
#define NBL_CONSTEXPR_STATIC_INLINE const static
#define NBL_CONSTEXPR_STATIC_FUNC static
#define NBL_CONSTEXPR_INLINE_FUNC inline
#define NBL_CONSTEXPR_STATIC_INLINE_FUNC static inline
#define NBL_CONSTEXPR_FORCED_INLINE_FUNC inline
#define NBL_CONST_MEMBER_FUNC
#define NBL_CONST_MEMBER_FUNC
#define NBL_IF_CONSTEXPR(...) if (__VA_ARGS__)

namespace nbl
{
Expand Down Expand Up @@ -100,4 +81,49 @@ struct add_pointer

#endif

namespace nbl
{
namespace hlsl
{
namespace impl
{
template<typename To, typename From, typename Enabled = void NBL_STRUCT_CONSTRAINABLE >
struct static_cast_helper
{
NBL_CONSTEXPR_STATIC_INLINE_FUNC To cast(NBL_CONST_REF_ARG(From) u)
{
#ifndef __HLSL_VERSION
return static_cast<To>(u);
#else
return To(u);
#endif
}
};

// CPP-side, this can invoke the copy constructor if the copy is non-trivial in generic code
// HLSL-side, this enables generic conversion code between types, contemplating the case where no conversion is needed
template<typename Same, typename Enabled>
struct static_cast_helper<Same, Same, Enabled>
{
NBL_CONSTEXPR_STATIC_INLINE_FUNC Same cast(NBL_CONST_REF_ARG(Same) s)
{
#ifndef __HLSL_VERSION
return static_cast<Same>(s);
#else
return s;
#endif
}
};

}

template<typename To, typename From>
NBL_CONSTEXPR_INLINE_FUNC To _static_cast(NBL_CONST_REF_ARG(From) v)
{
return impl::static_cast_helper<To, From>::cast(v);
}

}
}

#endif
72 changes: 69 additions & 3 deletions include/nbl/builtin/hlsl/cpp_compat/impl/intrinsics_impl.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ template<typename T NBL_STRUCT_CONSTRAINABLE>
struct all_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct any_helper;
template<typename B, typename T NBL_STRUCT_CONSTRAINABLE>
struct select_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct bitReverseAs_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
Expand Down Expand Up @@ -103,6 +105,10 @@ template<typename T NBL_STRUCT_CONSTRAINABLE>
struct nMax_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct nClamp_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct addCarry_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct subBorrow_helper;


#ifdef __HLSL_VERSION // HLSL only specializations
Expand All @@ -117,8 +123,8 @@ struct nClamp_helper;
// the template<> needs to be written ourselves
// return type is __VA_ARGS__ to protect against `,` in templated return types
#define AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(HELPER_NAME, SPIRV_FUNCTION_NAME, ARG_TYPE_LIST, ARG_TYPE_SET, ...)\
NBL_PARTIAL_REQ_TOP(is_same_v<decltype(spirv::SPIRV_FUNCTION_NAME<T>(BOOST_PP_SEQ_FOR_EACH_I(DECLVAL, _, ARG_TYPE_SET))), __VA_ARGS__ >) \
struct HELPER_NAME<BOOST_PP_SEQ_FOR_EACH_I(WRAP, _, ARG_TYPE_LIST) NBL_PARTIAL_REQ_BOT(is_same_v<decltype(spirv::SPIRV_FUNCTION_NAME<T>(BOOST_PP_SEQ_FOR_EACH_I(DECLVAL, _, ARG_TYPE_SET))), __VA_ARGS__ >) >\
NBL_PARTIAL_REQ_TOP(is_same_v<decltype(spirv::SPIRV_FUNCTION_NAME< BOOST_PP_SEQ_FOR_EACH_I(WRAP, _, ARG_TYPE_LIST) >(BOOST_PP_SEQ_FOR_EACH_I(DECLVAL, _, ARG_TYPE_SET))), __VA_ARGS__ >) \
struct HELPER_NAME<BOOST_PP_SEQ_FOR_EACH_I(WRAP, _, ARG_TYPE_LIST) NBL_PARTIAL_REQ_BOT(is_same_v<decltype(spirv::SPIRV_FUNCTION_NAME< BOOST_PP_SEQ_FOR_EACH_I(WRAP, _, ARG_TYPE_LIST) >(BOOST_PP_SEQ_FOR_EACH_I(DECLVAL, _, ARG_TYPE_SET))), __VA_ARGS__ >) >\
{\
using return_t = __VA_ARGS__;\
static inline return_t __call( BOOST_PP_SEQ_FOR_EACH_I(DECL_ARG, _, ARG_TYPE_SET) )\
Expand All @@ -139,8 +145,9 @@ template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(length_helper, length,
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(normalize_helper, normalize, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(rsqrt_helper, inverseSqrt, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(fract_helper, fract, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(all_helper, any, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(all_helper, all, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(any_helper, any, (T), (T), T)
template<typename B, typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(select_helper, select, (B)(T), (B)(T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(sign_helper, fSign, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(sign_helper, sSign, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(radians_helper, radians, (T), (T), T)
Expand All @@ -162,6 +169,9 @@ template<typename T, typename U> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(refract_hel
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nMax_helper, nMax, (T), (T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nMin_helper, nMin, (T), (T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nClamp_helper, nClamp, (T), (T)(T), T)
// Can use trivial case and not worry about restricting `T` with a concept since `spirv::AddCarryOutput / SubBorrowOutput` already take care of that
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(addCarry_helper, addCarry, (T), (T)(T), spirv::AddCarryOutput<T>)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(subBorrow_helper, subBorrow, (T), (T)(T), spirv::SubBorrowOutput<T>)

#define BITCOUNT_HELPER_RETRUN_TYPE conditional_t<is_vector_v<T>, vector<int32_t, vector_traits<T>::Dimension>, int32_t>
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(bitCount_helper, bitCount, (T), (T), BITCOUNT_HELPER_RETRUN_TYPE)
Expand Down Expand Up @@ -599,6 +609,62 @@ struct nClamp_helper<T>
}
};

// Once again no need to restrict the two below with concepts for same reason as HLSL version
template<typename T>
struct addCarry_helper
{
using return_t = spirv::AddCarryOutput<T>;
constexpr static inline return_t __call(const T operand1, const T operand2)
{
return_t retVal;
retVal.result = operand1 + operand2;
retVal.carry = T(retVal.result < operand1);
return retVal;
}
};

template<typename T>
struct subBorrow_helper
{
using return_t = spirv::SubBorrowOutput<T>;
constexpr static inline return_t __call(const T operand1, const T operand2)
{
return_t retVal;
retVal.result = static_cast<T>(operand1 - operand2);
retVal.borrow = T(operand1 < operand2);
return retVal;
}
};

template<typename B, typename T>
NBL_PARTIAL_REQ_TOP(concepts::BooleanScalar<B>)
struct select_helper<B, T NBL_PARTIAL_REQ_BOT(concepts::BooleanScalar<B>) >
{
NBL_CONSTEXPR_STATIC_INLINE_FUNC T __call(NBL_CONST_REF_ARG(B) condition, NBL_CONST_REF_ARG(T) object1, NBL_CONST_REF_ARG(T) object2)
{
return condition ? object1 : object2;
}
};

template<typename B, typename T>
NBL_PARTIAL_REQ_TOP(concepts::Boolean<B>&& concepts::Vector<B>&& concepts::Vector<T> && (extent_v<B> == extent_v<T>))
struct select_helper<B, T NBL_PARTIAL_REQ_BOT(concepts::Boolean<B>&& concepts::Vector<B>&& concepts::Vector<T> && (extent_v<B> == extent_v<T>)) >
{
NBL_CONSTEXPR_STATIC_INLINE_FUNC T __call(NBL_CONST_REF_ARG(B) condition, NBL_CONST_REF_ARG(T) object1, NBL_CONST_REF_ARG(T) object2)
{
using traits = hlsl::vector_traits<T>;
array_get<B, bool> conditionGetter;
array_get<T, typename traits::scalar_type> objectGetter;
array_set<T, typename traits::scalar_type> setter;

T selected;
for (uint32_t i = 0; i < traits::Dimension; ++i)
setter(selected, i, conditionGetter(condition, i) ? objectGetter(object1, i) : objectGetter(object2, i));

return selected;
}
};

#endif // C++ only specializations

// C++ and HLSL specializations
Expand Down
35 changes: 35 additions & 0 deletions include/nbl/builtin/hlsl/cpp_compat/impl/vector_impl.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef _NBL_BUILTIN_HLSL_CPP_COMPAT_IMPL_VECTOR_IMPL_INCLUDED_
#define _NBL_BUILTIN_HLSL_CPP_COMPAT_IMPL_VECTOR_IMPL_INCLUDED_

#include <nbl/builtin/hlsl/cpp_compat/basic.h>
#include <nbl/builtin/hlsl/cpp_compat/vector.hlsl>
#include <nbl/builtin/hlsl/concepts.hlsl>

// To prevent implicit truncation warnings
namespace nbl
{
namespace hlsl
{
namespace impl
{

template<typename T, uint16_t N, uint16_t M> NBL_PARTIAL_REQ_TOP(N <= M)
struct static_cast_helper<vector<T, N>, vector<T, M> NBL_PARTIAL_REQ_BOT(N <= M) >
{
NBL_CONSTEXPR_STATIC_INLINE_FUNC vector<T, N> cast(NBL_CONST_REF_ARG(vector<T, M>) val)
{
vector<T, N> retVal;
[[unroll]]
for (uint16_t i = 0; i < N; i++)
{
retVal[i] = val[i];
}
return retVal;
}
};

}
}
}

#endif
19 changes: 19 additions & 0 deletions include/nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ inline bool any(Vector vec)
return cpp_compat_intrinsics_impl::any_helper<Vector>::__call(vec);
}

template<typename Condition, typename ResultType>
NBL_CONSTEXPR_INLINE_FUNC ResultType select(Condition condition, ResultType object1, ResultType object2)
{
return cpp_compat_intrinsics_impl::select_helper<Condition, ResultType>::__call(condition, object1, object2);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but we already have mix in the #811 branch, shall we just make select(C,T,F) {return mix_helper<ResultType,Condition>::__call(F,T,C)} in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can drop this and just use mix, yeah

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok the thing is that select can either:

-take a bool and return just one of the objects entirely

-take a vector<bool, N> and return a mix of each object (provided the objects are vectors as well)

so the latter does exactly the same as mix, but it also can act as the usual ternary ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aaah ok mix doesn't work on structs, coordinate with @Przemog1 and @keptsecret later, so then mix would need to be done in terms of select_helper

/**
* @brief Returns x - floor(x).
*
Expand Down Expand Up @@ -217,6 +223,19 @@ inline T refract(NBL_CONST_REF_ARG(T) I, NBL_CONST_REF_ARG(T) N, NBL_CONST_REF_A
return cpp_compat_intrinsics_impl::refract_helper<T, U>::__call(I, N, eta);
}

template<typename T>
NBL_CONSTEXPR_INLINE_FUNC spirv::AddCarryOutput<T> addCarry(NBL_CONST_REF_ARG(T) operand1, NBL_CONST_REF_ARG(T) operand2)
{
return cpp_compat_intrinsics_impl::addCarry_helper<T>::__call(operand1, operand2);
}

template<typename T>
NBL_CONSTEXPR_INLINE_FUNC spirv::SubBorrowOutput<T> subBorrow(NBL_CONST_REF_ARG(T) operand1, NBL_CONST_REF_ARG(T) operand2)
{
return cpp_compat_intrinsics_impl::subBorrow_helper<T>::__call(operand1, operand2);
}


#ifdef __HLSL_VERSION
#define NAMESPACE spirv
#else
Expand Down
Loading