Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 45 additions & 14 deletions include/nbl/builtin/hlsl/bda/__ptr.hlsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
// This file is part of the "Nabla Engine".
// For conditions of distribution and use, see copyright notice in nabla.h

#include "nbl/builtin/hlsl/type_traits.hlsl"
#include "nbl/builtin/hlsl/bda/__ref.hlsl"

Expand All @@ -17,32 +16,64 @@ namespace bda
template<typename T>
struct __ptr
{
using this_t = __ptr <T>;
uint64_t addr;
using this_t = __ptr<T>;
uint32_t2 addr;

static this_t create(const uint64_t _addr)
static this_t create(const uint32_t2 _addr)
{
this_t retval;
retval.addr = _addr;
return retval;
}

template< uint64_t alignment=alignment_of_v<T> >
__ref<T,alignment,false> deref()
// in non-64bit mode we only support "small" arithmetic on pointers (just offsets no arithmetic on pointers)
__ptr operator+(uint32_t i)
{
i *= sizeof(T);
uint32_t2 newAddr = addr;
spirv::AddCarryOutput<uint32_t> lsbAddRes = spirv::addCarry<uint32_t>(addr[0],i);
newAddr[0] = lsbAddRes.result;
newAddr[1] += lsbAddRes.carry;
return __ptr::create(newAddr);
}
__ptr operator-(uint32_t i)
{
i *= sizeof(T);
uint32_t2 newAddr = addr;
spirv::AddCarryOutput<uint32_t> lsbSubRes = spirv::subBorrow<uint32_t>(addr[0],i);
newAddr[0] = lsbSubRes.result;
newAddr[1] -= lsbSubRes.carry;
return __ptr::create(newAddr);
}

template<uint64_t alignment=alignment_of_v<T>, bool _restrict=false>
__ref<T,alignment,_restrict> deref()
{
// TODO: assert(addr&uint64_t(alignment-1)==0);
using retval_t = __ref < T, alignment, false>;
retval_t retval;
retval.__init(addr);
__ref<T,alignment,_restrict> retval;
retval.__init(spirv::bitcast<spirv::bda_pointer_t<T>,uint32_t2>(addr));
return retval;
}

template<uint64_t alignment=alignment_of_v<T> >
__ref<T,alignment,true> deref_restrict() {return deref<alignment,true>();}

__ptr operator +(int64_t i) {
return __ptr::create(addr + sizeof(T) * i);
//! Dont use these, to avoid emitting shaderUint64 capability when compiling for crappy mobile GPUs
static this_t create(const uint64_t _addr)
{
this_t retval;
retval.addr = spirv::bitcast<uint32_t2>(_addr);
return retval;
}

__ptr operator-(int64_t i) {
return __ptr::create(addr - sizeof(T) * i);
__ptr operator+(int64_t i)
{
i *= sizeof(T);
return __ptr::create(spirv::bitcast<uint64_t>(addr)+i);
}
__ptr operator-(int64_t i)
{
i *= sizeof(T);
return __ptr::create(spirv::bitcast<uint64_t>(addr)-i);
}
};

Expand Down
48 changes: 25 additions & 23 deletions include/nbl/builtin/hlsl/bda/__ref.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,44 @@
#ifndef _NBL_BUILTIN_HLSL_BDA_REF_INCLUDED_
#define _NBL_BUILTIN_HLSL_BDA_REF_INCLUDED_

// TODO: this shouldn't be included IMHO
#include "nbl/builtin/hlsl/functional.hlsl"
#include "nbl/builtin/hlsl/spirv_intrinsics/core.hlsl"

namespace nbl
{
namespace hlsl
{
namespace bda
{
template<typename T, bool _restrict>
struct __spv_ptr_t;
template<typename T>
using __spv_ptr_t __NBL_CAPABILITY_PhysicalStorageBufferAddresses = spirv::pointer_t<spv::StorageClassPhysicalStorageBuffer,T>;

struct __spv_ptr_t<T,false>
{
[[vk::ext_decorate(spv::DecorationAliasedPointer)]] spirv::bda_pointer_t<T> value;
};
template<typename T>
struct __ptr;
struct __spv_ptr_t<T,true>
{
[[vk::ext_decorate(spv::DecorationRestrictPointer)]] spirv::bda_pointer_t<T> value;
};

// TODO: refactor this in terms of `nbl::hlsl::` when they fix the composite struct inline SPIR-V BDA issue
template<typename T, uint32_t alignment, bool _restrict>
struct __base_ref
{
// TODO:
// static_assert(alignment>=alignof(T));
__spv_ptr_t<T,_restrict> ptr;

using spv_ptr_t = uint64_t;
spv_ptr_t ptr;

__spv_ptr_t<T> __get_spv_ptr()
void __init(const spirv::bda_pointer_t<T> _ptr)
{
return spirv::bitcast < __spv_ptr_t<T> > (ptr);
ptr.value = _ptr;
}

// TODO: Would like to use `spv_ptr_t` or OpAccessChain result instead of `uint64_t`
void __init(const spv_ptr_t _ptr)

spirv::bda_pointer_t<T> __get_spv_ptr()
{
ptr = _ptr;
// BUG: https://github.com/microsoft/DirectXShaderCompiler/issues/7184
// if I don't launder the pointer through this I get "IsNonPtrAccessChain(ptrInst->opcode())"
return spirv::copyObject<spirv::bda_pointer_t<T> >(ptr.value);
}

T load()
Expand All @@ -50,16 +55,13 @@ struct __base_ref
}
};

template<typename T, uint32_t alignment=alignment_of_v<T>, bool _restrict = false>
// TODO: I wish HLSL had some things like C++ which would allow you to make a "stack only"/non-storable type
// NOTE: I guess there's the Function/Private storage space variables?
template<typename T, uint32_t alignment=alignment_of_v<T>, bool _restrict=false>
struct __ref : __base_ref<T,alignment,_restrict>
{
using base_t = __base_ref < T, alignment, _restrict>;
using this_t = __ref < T, alignment, _restrict>;

__spv_ptr_t<T> get_ptr()
{
return base_t::__get_spv_ptr();
}
using base_t = __base_ref< T,alignment,_restrict>;
using this_t = __ref<T,alignment,_restrict>;
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions include/nbl/builtin/hlsl/bda/bda_accessor.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ struct BdaAccessor : impl::BdaAccessorBase
atomicAdd(const uint64_t index, const T value)
{
bda::__ptr<T> target = ptr + index;
return glsl::atomicAdd(target.template deref().get_ptr(), value);
return glsl::atomicAdd(target.template deref().ptr.value, value);
}

template<typename S = T>
enable_if_t<is_same_v<S,T> && is_integral<T>::value && (sizeof(T) == 4 || sizeof(T) == 8), T>
atomicSub(const uint64_t index, const T value)
{
bda::__ptr<T> target = ptr + index;
return glsl::atomicSub(target.template deref().get_ptr(), value);
return glsl::atomicSub(target.template deref().ptr.value, value);
}

bda::__ptr<T> ptr;
Expand Down
176 changes: 176 additions & 0 deletions include/nbl/builtin/hlsl/bda/struct_declare.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
// This file is part of the "Nabla Engine".
// For conditions of distribution and use, see copyright notice in nabla.h
#ifndef _NBL_BUILTIN_HLSL_BDA_STRUCT_DECLARE_INCLUDED_
#define _NBL_BUILTIN_HLSL_BDA_STRUCT_DECLARE_INCLUDED_

#include "nbl/builtin/hlsl/type_traits.hlsl"
#include "nbl/builtin/hlsl/mpl.hlsl"
#ifdef __HLSL_VERSION
#include "nbl/builtin/hlsl/bda/__ptr.hlsl"
#endif // __HLSL_VERSION


namespace nbl
{
namespace hlsl
{
namespace bda
{
// silly utility traits
template<typename T>
struct member_count
{
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = 0;
};
template<typename T>
NBL_CONSTEXPR uint32_t member_count_v = member_count<T>::value;

template<typename T, int32_t MemberIx>
struct member_type;
template<typename T, int32_t MemberIx>
using member_type_t = typename member_type<T,MemberIx>::type;

// default alignment is the alignment of the type
template<typename T, int32_t MemberIx>
struct member_alignment
{
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = alignment_of_v<member_type_t<T,MemberIx> >;
};
template<typename T, int32_t MemberIx>
NBL_CONSTEXPR uint32_t member_alignment_v = member_alignment<T,MemberIx>::value;

// the default specialization of the offset assumes scalar layout
template<typename T, int32_t MemberIx>
struct member_offset
{
// TODO: assert that the custom alignment is no less than the type's natural alignment?
// first byte past previous member, rounded up to out alignment
NBL_CONSTEXPR_STATIC_INLINE uint64_t value = mpl::align_up_v<member_offset<T,MemberIx-1>::value+size_of_v<member_type_t<T,MemberIx-1> >,member_alignment_v<T,MemberIx> >;
};
template<typename T>
struct member_offset<T,0>
{
NBL_CONSTEXPR_STATIC_INLINE uint64_t value = 0;
};
template<typename T, int32_t MemberIx>
NBL_CONSTEXPR uint64_t member_offset_v = member_offset<T,MemberIx>::value;

// stuff needed to compute alignment of the struct properly
namespace impl
{
template<typename T, uint32_t N>
struct default_alignment
{
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = mpl::max_v<uint32_t,member_alignment_v<T,N-1>,default_alignment<T,N-1>::value>;
};
// le invalid values
template<typename T>
struct default_alignment<T,0>
{
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = 0;
};
template<typename T, typename MemberCount=member_count<T> >
NBL_CONSTEXPR uint32_t default_alignment_v = default_alignment<T,MemberCount::value>::value;
}
}
}
}

//! Need to gen identical struct in HLSL and C++, right now this tool can declare non-templated structs and full explicit specialized ones

//implementation details
#define NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE(identifier,...) __VA_ARGS__
#define NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME(identifier,...) identifier
#define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_TYPE(r,IDENTIFIER,i,e) template<> \
struct ::nbl::hlsl::bda::member_type<NBL_EVAL IDENTIFIER,i> \
{ \
using type = NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e; \
};

//! TODO: handle declarations for partial template specializations and non-specializations
#define NBL_HLSL_IMPL_DECLARE_STRUCT_MEMBER(identifier,...) __VA_ARGS__ identifier;
#ifdef __HLSL_VERSION
#define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER(r,IDENTIFIER,i,e) [[vk::ext_decorate(spv::DecorationOffset,::nbl::hlsl::bda::member_offset_v<NBL_EVAL IDENTIFIER,i>)]] NBL_HLSL_IMPL_DECLARE_STRUCT_MEMBER e
#define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_REFERENCE(r,unused,i,e) ::nbl::hlsl::bda::__ref< \
NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e, \
::nbl::hlsl::mpl::min_v<uint32_t,::nbl::hlsl::bda::member_alignment_v<__referenced_t,i>,alignment>, \
_restrict> NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME e;
#define NBL_HLSL_IMPL_INIT_STRUCT_MEMBER_REFERENCE(r,unused,i,e) NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME e .__init( \
::nbl::hlsl::spirv::accessChain<NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e>(base_t::ptr.value,i) \
);
#define NBL_HLSL_IMPL_DEFINE_STRUCT(IDENTIFIER,MEMBER_SEQ) NBL_EVAL IDENTIFIER \
{ \
BOOST_PP_SEQ_FOR_EACH_I(NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER,IDENTIFIER,MEMBER_SEQ) \
}; \
template<uint32_t alignment, bool _restrict> \
struct ::nbl::hlsl::bda::__ref<NBL_EVAL IDENTIFIER,alignment,_restrict> : ::nbl::hlsl::bda::__base_ref<NBL_EVAL IDENTIFIER,alignment,_restrict> \
{ \
using __referenced_t = NBL_EVAL IDENTIFIER; \
using base_t = __base_ref<__referenced_t,alignment,_restrict>; \
using this_t = __ref<__referenced_t,alignment,_restrict>; \
\
BOOST_PP_SEQ_FOR_EACH_I(NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_REFERENCE,dummy,MEMBER_SEQ) \
\
void __init(const ::nbl::hlsl::spirv::bda_pointer_t<__referenced_t> _ptr) \
{ \
base_t::__init(_ptr); \
BOOST_PP_SEQ_FOR_EACH_I(NBL_HLSL_IMPL_INIT_STRUCT_MEMBER_REFERENCE,dummy,MEMBER_SEQ) \
} \
}
#else
#define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER(r,IDENTIFIER,i,e) alignas(::nbl::hlsl::bda::member_alignment_v<NBL_EVAL IDENTIFIER,i>) NBL_HLSL_IMPL_DECLARE_STRUCT_MEMBER e
#define NBL_HLSL_IMPL_DEFINE_STRUCT(IDENTIFIER,MEMBER_SEQ) alignas(::nbl::hlsl::alignment_of_v<NBL_EVAL IDENTIFIER >) NBL_EVAL IDENTIFIER \
{ \
BOOST_PP_SEQ_FOR_EACH_I(NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER,IDENTIFIER,MEMBER_SEQ) \
}
#endif

// some weird stuff to handle alignment
#define NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN(IDENTIFIER,MEMBER_SEQ) template<> \
struct ::nbl::hlsl::bda::member_count<NBL_EVAL IDENTIFIER > \
{ \
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = BOOST_PP_SEQ_SIZE(MEMBER_SEQ); \
}; \
BOOST_PP_SEQ_FOR_EACH_I(NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_TYPE,IDENTIFIER,MEMBER_SEQ) \
template <> \
struct ::nbl::hlsl::alignment_of<NBL_EVAL IDENTIFIER > \
{
#define NBL_HLSL_IMPL_DEFINE_STRUCT_END(IDENTIFIER,MEMBER_SEQ,...) }; \
template<> \
struct ::nbl::hlsl::size_of<NBL_EVAL IDENTIFIER > \
{ \
using type = NBL_EVAL IDENTIFIER; \
NBL_CONSTEXPR_STATIC_INLINE uint32_t __last_member_ix_v = ::nbl::hlsl::bda::member_count_v<type>-1; \
NBL_CONSTEXPR_STATIC_INLINE uint64_t __last_member_offset_v = ::nbl::hlsl::bda::member_offset_v<type, __last_member_ix_v>; \
NBL_CONSTEXPR_STATIC_INLINE uint64_t __last_member_size_v = ::nbl::hlsl::size_of_v<::nbl::hlsl::bda::member_type_t<type, __last_member_ix_v> >; \
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = ::nbl::hlsl::mpl::align_up_v<__last_member_offset_v + __last_member_size_v, alignment_of_v<type > >; \
\
__VA_ARGS__ \
\
}; \
struct NBL_HLSL_IMPL_DEFINE_STRUCT(IDENTIFIER,MEMBER_SEQ)

#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/size.hpp>
// MEMBER_SEQ is to be a sequence of variable name and type (identifier0,Type0)...(identifierN,TypeN) @see NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE
// the VA_ARGS is the struct alignment for alignas, usage example
// ```
// NBL_HLSL_DEFINE_STRUCT((MyStruct2),
// ((a, float32_t))
// ((b, int32_t))
// ((c, int32_t2)),
//
// ... block of code for the methods ...
//
// );
// ```
#define NBL_HLSL_DEFINE_STRUCT(IDENTIFIER,MEMBER_SEQ,...) NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN(IDENTIFIER,MEMBER_SEQ) \
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = ::nbl::hlsl::bda::impl::default_alignment_v<NBL_EVAL IDENTIFIER >; \
NBL_HLSL_IMPL_DEFINE_STRUCT_END(IDENTIFIER,MEMBER_SEQ,__VA_ARGS__)
// version allowing custom alignment on whole struct
#define NBL_HLSL_DEFINE_ALIGNAS_STRUCT(IDENTIFIER,ALIGNMENT,MEMBER_SEQ,...) NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN(IDENTIFIER,MEMBER_SEQ) \
NBL_CONSTEXPR_STATIC_INLINE uint32_t value = ALIGNMENT; \
NBL_HLSL_IMPL_DEFINE_STRUCT_END(IDENTIFIER,MEMBER_SEQ,__VA_ARGS__)

#endif
1 change: 1 addition & 0 deletions include/nbl/builtin/hlsl/complex.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace nbl
namespace hlsl
{

// TODO: make this BDA compatible (no unspecialized templates yet)
template<typename Scalar>
struct complex_t
{
Expand Down
Loading