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