Skip to content

New morton class with arithmetic and comparison operators #860

New issue

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

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

Already on GitHub? # 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 all 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
18 changes: 9 additions & 9 deletions include/nbl/builtin/hlsl/algorithm.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -18,71 +18,71 @@ namespace impl
// TODO: use structs

template<typename T>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(uint16_t) lhs, NBL_REF_ARG(uint16_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(uint16_t) lhs, NBL_REF_ARG(uint16_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(uint32_t) lhs, NBL_REF_ARG(uint32_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(uint32_t) lhs, NBL_REF_ARG(uint32_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(uint64_t) lhs, NBL_REF_ARG(uint64_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(uint64_t) lhs, NBL_REF_ARG(uint64_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(int16_t) lhs, NBL_REF_ARG(int16_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(int16_t) lhs, NBL_REF_ARG(int16_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(int32_t) lhs, NBL_REF_ARG(int32_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(int32_t) lhs, NBL_REF_ARG(int32_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}

template<>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(int64_t) lhs, NBL_REF_ARG(int64_t) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(int64_t) lhs, NBL_REF_ARG(int64_t) rhs)
{
lhs ^= rhs;
rhs ^= lhs;
lhs ^= rhs;
}
#else
template<typename T>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
{
std::swap(lhs, rhs);
}
#endif
}

template<typename T>
NBL_CONSTEXPR_INLINE_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
NBL_CONSTEXPR_FUNC void swap(NBL_REF_ARG(T) lhs, NBL_REF_ARG(T) rhs)
{
impl::swap<T>(lhs, rhs);
}
Expand Down
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
4 changes: 4 additions & 0 deletions include/nbl/builtin/hlsl/cpp_compat.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
// it includes vector and matrix
#include <nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl>
#include <nbl/builtin/hlsl/cpp_compat/promote.hlsl>
#include <nbl/builtin/hlsl/cpp_compat/truncate.hlsl>

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

#endif
73 changes: 40 additions & 33 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,12 @@ 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
Copy link
Member

Choose a reason for hiding this comment

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

constexpr implies inline for functions (not variables)

([dcl.constexpr], §7.1.5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1.2)."

Choose a reason for hiding this comment

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

you can use CONSTEXPR_FUNC instead

Choose a reason for hiding this comment

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

seems that NBL_CONSTEXPR_INLINE_FUNC and NBL_CONSTEXPR_STATIC_INLINE_FUNC should be removed

the constexpr inline and constexpr static inline only make sense for variables

#define NBL_CONSTEXPR_STATIC_INLINE constexpr static inline
#define NBL_CONSTEXPR_INLINE_FUNC constexpr inline
#define NBL_CONSTEXPR_STATIC_FUNC constexpr static
#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 +39,17 @@ 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_FUNC inline
#define NBL_CONSTEXPR_STATIC const static
#define NBL_CONSTEXPR_INLINE const static
#define NBL_CONSTEXPR_STATIC_INLINE const static
#define NBL_CONSTEXPR_INLINE_FUNC inline
#define NBL_CONSTEXPR_STATIC_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 +77,34 @@ 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_FUNC To cast(NBL_CONST_REF_ARG(From) u)
{
#ifndef __HLSL_VERSION
return static_cast<To>(u);
#else
return To(u);
#endif
}
};

}

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

}
}

#endif
85 changes: 82 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 @@ -104,6 +106,12 @@ 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;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct undef_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct fma_helper;

#ifdef __HLSL_VERSION // HLSL only specializations
Expand All @@ -118,8 +126,8 @@ struct fma_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 @@ -141,8 +149,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 @@ -164,6 +173,10 @@ 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>)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(undef_helper, undef, (T), , T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(fma_helper, fma, (T), (T)(T)(T), T)

#define BITCOUNT_HELPER_RETRUN_TYPE conditional_t<is_vector_v<T>, vector<int32_t, vector_traits<T>::Dimension>, int32_t>
Expand Down Expand Up @@ -602,6 +615,72 @@ 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_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_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;
}
};

template<typename T>
struct undef_helper
{
NBL_CONSTEXPR_STATIC_FUNC T __call()
{
T t;
return t;
}
};

template<typename FloatingPoint>
requires concepts::FloatingPointScalar<FloatingPoint>
struct fma_helper<FloatingPoint>
Expand Down
Loading