1+ // Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
2+ // This file is part of the "Nabla Engine".
3+ // For conditions of distribution and use, see copyright notice in nabla.h
4+ #ifndef _NBL_BUILTIN_HLSL_BDA_STRUCT_DECLARE_INCLUDED_
5+ #define _NBL_BUILTIN_HLSL_BDA_STRUCT_DECLARE_INCLUDED_
6+
7+ #include "nbl/builtin/hlsl/type_traits.hlsl"
8+ #include "nbl/builtin/hlsl/mpl.hlsl"
9+ #ifdef __HLSL_VERSION
10+ #include "nbl/builtin/hlsl/bda/__ptr.hlsl"
11+ #endif // __HLSL_VERSION
12+
13+
14+ namespace nbl
15+ {
16+ namespace hlsl
17+ {
18+ namespace bda
19+ {
20+ // silly utility traits
21+ template<typename T>
22+ struct member_count
23+ {
24+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = 0 ;
25+ };
26+ template<typename T>
27+ NBL_CONSTEXPR uint32_t member_count_v = member_count<T>::value;
28+
29+ template<typename T, int32_t MemberIx>
30+ struct member_type;
31+ template<typename T, int32_t MemberIx>
32+ using member_type_t = typename member_type<T,MemberIx>::type;
33+
34+ // default alignment is the alignment of the type
35+ template<typename T, int32_t MemberIx>
36+ struct member_alignment
37+ {
38+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = alignment_of_v<member_type_t<T,MemberIx> >;
39+ };
40+ template<typename T, int32_t MemberIx>
41+ NBL_CONSTEXPR uint32_t member_alignment_v = member_alignment<T,MemberIx>::value;
42+
43+ // the default specialization of the offset assumes scalar layout
44+ template<typename T, int32_t MemberIx>
45+ struct member_offset
46+ {
47+ // TODO: assert that the custom alignment is no less than the type's natural alignment?
48+ // first byte past previous member, rounded up to out alignment
49+ 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> >;
50+ };
51+ template<typename T>
52+ struct member_offset<T,0 >
53+ {
54+ NBL_CONSTEXPR_STATIC_INLINE uint64_t value = 0 ;
55+ };
56+ template<typename T, int32_t MemberIx>
57+ NBL_CONSTEXPR uint64_t member_offset_v = member_offset<T,MemberIx>::value;
58+
59+ // stuff needed to compute alignment of the struct properly
60+ namespace impl
61+ {
62+ template<typename T, uint32_t N>
63+ struct default_alignment
64+ {
65+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = mpl::max_v<uint32_t,member_alignment_v<T,N-1 >,default_alignment<T,N-1 >::value>;
66+ };
67+ // le invalid values
68+ template<typename T>
69+ struct default_alignment<T,0 >
70+ {
71+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = 0 ;
72+ };
73+ template<typename T, typename MemberCount=member_count<T> >
74+ NBL_CONSTEXPR uint32_t default_alignment_v = default_alignment<T,MemberCount::value>::value;
75+ }
76+ }
77+ }
78+ }
79+
80+ //! Need to gen identical struct in HLSL and C++, right now this tool can declare non-templated structs and full explicit specialized ones
81+
82+ //implementation details
83+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE (identifier,...) __VA_ARGS__
84+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME (identifier,...) identifier
85+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_TYPE (r,IDENTIFIER,i,e) template<> \
86+ struct ::nbl::hlsl::bda::member_type<NBL_EVAL IDENTIFIER,i> \
87+ { \
88+ using type = NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e; \
89+ };
90+
91+ //! TODO: handle declarations for partial template specializations and non-specializations
92+ #define NBL_HLSL_IMPL_DECLARE_STRUCT_MEMBER (identifier,...) __VA_ARGS__ identifier;
93+ #ifdef __HLSL_VERSION
94+ #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
95+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_REFERENCE (r,unused,i,e) ::nbl::hlsl::bda::__ref< \
96+ NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e, \
97+ ::nbl::hlsl::mpl::min_v<uint32_t,::nbl::hlsl::bda::member_alignment_v<__referenced_t,i>,alignment>, \
98+ _restrict> NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME e;
99+ #define NBL_HLSL_IMPL_INIT_STRUCT_MEMBER_REFERENCE (r,unused,i,e) NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_NAME e .__init ( \
100+ ::nbl::hlsl::spirv::accessChain<NBL_HLSL_IMPL_DEFINE_STRUCT_GET_MEMBER_TYPE e>(base_t::ptr.value,i) \
101+ );
102+ #define NBL_HLSL_IMPL_DEFINE_STRUCT (IDENTIFIER,MEMBER_SEQ) NBL_EVAL IDENTIFIER \
103+ { \
104+ BOOST_PP_SEQ_FOR_EACH_I (NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER,IDENTIFIER,MEMBER_SEQ) \
105+ }; \
106+ template<uint32_t alignment, bool _restrict> \
107+ struct ::nbl::hlsl::bda::__ref<NBL_EVAL IDENTIFIER,alignment,_restrict> : ::nbl::hlsl::bda::__base_ref<NBL_EVAL IDENTIFIER,alignment,_restrict> \
108+ { \
109+ using __referenced_t = NBL_EVAL IDENTIFIER; \
110+ using base_t = __base_ref<__referenced_t,alignment,_restrict>; \
111+ using this_t = __ref<__referenced_t,alignment,_restrict>; \
112+ \
113+ BOOST_PP_SEQ_FOR_EACH_I (NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_REFERENCE,dummy,MEMBER_SEQ) \
114+ \
115+ void __init (const ::nbl::hlsl::spirv::bda_pointer_t<__referenced_t> _ptr) \
116+ { \
117+ base_t::__init (_ptr); \
118+ BOOST_PP_SEQ_FOR_EACH_I (NBL_HLSL_IMPL_INIT_STRUCT_MEMBER_REFERENCE,dummy,MEMBER_SEQ) \
119+ } \
120+ }
121+ #else
122+ #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
123+ #define NBL_HLSL_IMPL_DEFINE_STRUCT (IDENTIFIER,MEMBER_SEQ) alignas (::nbl::hlsl::alignment_of_v<NBL_EVAL IDENTIFIER >) NBL_EVAL IDENTIFIER \
124+ { \
125+ BOOST_PP_SEQ_FOR_EACH_I (NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER,IDENTIFIER,MEMBER_SEQ) \
126+ }
127+ #endif
128+
129+ // some weird stuff to handle alignment
130+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN (IDENTIFIER,MEMBER_SEQ) template<> \
131+ struct ::nbl::hlsl::bda::member_count<NBL_EVAL IDENTIFIER > \
132+ { \
133+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = BOOST_PP_SEQ_SIZE (MEMBER_SEQ); \
134+ }; \
135+ BOOST_PP_SEQ_FOR_EACH_I (NBL_HLSL_IMPL_DEFINE_STRUCT_MEMBER_TYPE,IDENTIFIER,MEMBER_SEQ) \
136+ template <> \
137+ struct ::nbl::hlsl::alignment_of<NBL_EVAL IDENTIFIER > \
138+ {
139+ #define NBL_HLSL_IMPL_DEFINE_STRUCT_END (IDENTIFIER,MEMBER_SEQ,...) }; \
140+ template<> \
141+ struct ::nbl::hlsl::size_of<NBL_EVAL IDENTIFIER > \
142+ { \
143+ using type = NBL_EVAL IDENTIFIER; \
144+ NBL_CONSTEXPR_STATIC_INLINE uint32_t __last_member_ix_v = ::nbl::hlsl::bda::member_count_v<type>-1 ; \
145+ NBL_CONSTEXPR_STATIC_INLINE uint64_t __last_member_offset_v = ::nbl::hlsl::bda::member_offset_v<type, __last_member_ix_v>; \
146+ 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> >; \
147+ 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 > >; \
148+ \
149+ __VA_ARGS__ \
150+ \
151+ }; \
152+ struct NBL_HLSL_IMPL_DEFINE_STRUCT (IDENTIFIER,MEMBER_SEQ)
153+
154+ #include <boost/preprocessor/seq/for_each_i.hpp>
155+ #include <boost/preprocessor/seq/size.hpp>
156+ // 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
157+ // the VA_ARGS is the struct alignment for alignas, usage example
158+ // ```
159+ // NBL_HLSL_DEFINE_STRUCT((MyStruct2),
160+ // ((a, float32_t))
161+ // ((b, int32_t))
162+ // ((c, int32_t2)),
163+ //
164+ // ... block of code for the methods ...
165+ //
166+ // );
167+ // ```
168+ #define NBL_HLSL_DEFINE_STRUCT (IDENTIFIER,MEMBER_SEQ,...) NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN (IDENTIFIER,MEMBER_SEQ) \
169+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = ::nbl::hlsl::bda::impl::default_alignment_v<NBL_EVAL IDENTIFIER >; \
170+ NBL_HLSL_IMPL_DEFINE_STRUCT_END (IDENTIFIER,MEMBER_SEQ,__VA_ARGS__)
171+ // version allowing custom alignment on whole struct
172+ #define NBL_HLSL_DEFINE_ALIGNAS_STRUCT (IDENTIFIER,ALIGNMENT,MEMBER_SEQ,...) NBL_HLSL_IMPL_DEFINE_STRUCT_BEGIN (IDENTIFIER,MEMBER_SEQ) \
173+ NBL_CONSTEXPR_STATIC_INLINE uint32_t value = ALIGNMENT; \
174+ NBL_HLSL_IMPL_DEFINE_STRUCT_END (IDENTIFIER,MEMBER_SEQ,__VA_ARGS__)
175+
176+ #endif
0 commit comments