Skip to content

Conversation

@Fletterio
Copy link
Contributor

Description

Adds a new class for 2,3 and 4-dimensional morton codes, with arithmetic and comparison operators

Testing

TODO

TODO list:

Need to make sure all operators work properly before merging

*/
template<typename I>
NBL_CONSTEXPR_STATIC_FUNC enable_if_t<is_integral_v<I> && is_scalar_v<I> && (is_signed_v<I> == Signed), this_t>
NBL_CONSTEXPR_STATIC_FUNC enable_if_t<is_integral_v<I> && is_scalar_v<I> && (is_signed_v<I> == Signed) && (8 * sizeof(I) >= Bits), this_t>

Choose a reason for hiding this comment

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

no need to check && (8 * sizeof(I) >= Bits) calling into impl::Transcoder should already check this

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.


template<typename I>
explicit code(NBL_CONST_REF_ARG(vector<I, D>) cartesian)
template<typename I NBL_FUNC_REQUIRES(8 * sizeof(I) >= Bits)

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

Comment on lines 524 to 526
// I must be of same signedness as the morton code, and be wide enough to hold each component
template<typename I, uint16_t Bits, uint16_t D, typename _uint64_t> NBL_PARTIAL_REQ_TOP(concepts::IntegralScalar<I> && 8 * sizeof(I) >= Bits)
struct static_cast_helper<vector<I, D>, morton::code<is_signed_v<I>, Bits, D, _uint64_t> NBL_PARTIAL_REQ_BOT(concepts::IntegralScalar<I> && 8 * sizeof(I) >= Bits) >

Choose a reason for hiding this comment

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

the bitcount >= the transcoder will already check for you

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

// Specialize the `static_cast_helper`
namespace impl
template <bool Signed, uint16_t Bits, uint16_t D, typename _uint64_t NBL_PRIMARY_REQUIRES(morton::impl::Dimension<D>&& D* Bits <= 64)
template <typename I NBL_FUNC_REQUIRES(8 * sizeof(I) >= Bits && is_signed_v<I> == Signed)

Choose a reason for hiding this comment

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

again, its a bit cumbersome to check bitcount here and in other places

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

Comment on lines 75 to +91
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;
Copy link
Member

@devshgraphicsprogramming devshgraphicsprogramming Nov 29, 2025

Choose a reason for hiding this comment

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

aren;t these specs backward? as in returning false for emulated float

It should be FloatingPointLikeScalar = FloatingPointScalar || impl::is_emulating_floating_point_scalar
https://godbolt.devsh.eu/z/dbjvfj

The default spec of is_emulating_floating_point_scalar should be false

Choose a reason for hiding this comment

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

thats actually a bug ever since @Przemog1's PR

Copy link
Contributor

@kevyuu kevyuu Dec 2, 2025

Choose a reason for hiding this comment

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

It behave as how it is described in the comment. is_emulating_floating_point_scalar return true both for float64_t and emulated_float64_t. It is specialized here for emulated_float64_t

struct is_emulating_floating_point_scalar<emulated_float64_t<FastMath, FlushDenormToZero> >

Should we change it so that only emulated_float64_t return true for is_emulating_floating_point_scalar and false for everything else, and keep FloatingPointLikeScalar like how it is?


NBL_CONSTEXPR_FUNC T operator()(NBL_CONST_REF_ARG(T) operand)
{
return -operand;

Choose a reason for hiding this comment

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

doesn't it need to be operand.operator-() because of HLSL?

or maybe you want to do a partial spec with requires Fundamental<T> and requires !Fundamental<T> where you do operator-() call ?


struct emulated_int64_t
{
using storage_t = vector<uint32_t, 2>;

Choose a reason for hiding this comment

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

can be moved to "int64_common_member_inc.hlsl"

Comment on lines +78 to +79
template<>
struct is_emulating_integral_scalar<emulated_uint64_t>

Choose a reason for hiding this comment

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

where's the primary template declaration?

btw you could actually replace impl::is_emulating_integral_scalar with just ImitationIntegral64Scalar concept

return *this;
}
template <typename T>
NBL_BOOL_CONCEPT ImitationIntegral64Scalar = same_as<T, emulated_uint64_t> || same_as<T, emulated_int64_t>;

Choose a reason for hiding this comment

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

rename Imitation to Emulated


template<typename Scalar, typename U>
struct Promote<vector <Scalar, 2>, U>
// TODO(kevinyu): Should we enable truncation from uint64_t to emulated_vector<emulated_uint64_t, N>?

Choose a reason for hiding this comment

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

promotion yes, allow it

}
};

// The default version above only works for fundamental scalars, vectors and matrices. This is because you can't call `~x` unless `x` is one of the former.

Choose a reason for hiding this comment

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

then constrain the version above to only do FundamentalType

the thing which you have as a specialization you should have as the general case, and the general you should have as a specialization

Comment on lines +273 to +282
template<typename T NBL_STRUCT_CONSTRAINABLE >
struct ternary_operator
{
using type_t = T;

T operator()(bool condition, NBL_CONST_REF_ARG(T) lhs, NBL_CONST_REF_ARG(T) rhs)
NBL_CONSTEXPR_FUNC T operator()(NBL_CONST_REF_ARG(bool) condition, NBL_CONST_REF_ARG(T) lhs, NBL_CONST_REF_ARG(T) rhs)
{
return select<bool, T>(condition, lhs, rhs);
}
};

Choose a reason for hiding this comment

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

hmm actually I noticed something, in C++ and HLSL the ? shortcircuits (whereas select shouldn't)

This means that ternary_operator can only be defined as

template<typename F1, typename F2> requires is_same_v<decltype(std::declval<F1>()()),decltype(std::declval<F2>()())>
struct ternary_operator
{
   using type_t = decltype(std::declval<F1>().operator());

   NBL_CONSTEXPR_FUNC type_t operator()(const bool condition, NBL_CONST_REF_ARG(F1) lhs, NBL_CONST_REF_ARG(F2) rhs)
   {
      if (condition)
         return lhs();
      else
         return rhs();
   }
};

simply to take lambdas and short-circuit (not call/evaluate the branch that is false)

so sorry about telling you to reimplement ternary_operator in terms of select
(but most ccrrent uses of ternary_operator should be replaced with select)

Choose a reason for hiding this comment

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

In Nabla itself there should only be this, which needs to change to select_helper partial spec

struct ternary_operator< complex_t<Scalar> >

Choose a reason for hiding this comment

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

return leftShift(interleaved, truncate<vector<uint16_t, Dim> >(vector<uint16_t, 4>(0, 1, 2, 3)));
}

template<typename decode_t = conditional_t<(Bits > 16), vector<uint32_t, Dim>, vector<uint16_t, Dim> > >

Choose a reason for hiding this comment

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

if would be better to make the default value a constraint instead which checks that is_same_v<conditional<...>,decode_t>

cause right now I can slam any type I want in and override the default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants