Skip to content

Commit 4de03b9

Browse files
author
devsh
committed
draft of backport to uint32_t2
1 parent 9caf185 commit 4de03b9

File tree

4 files changed

+116
-44
lines changed

4 files changed

+116
-44
lines changed

include/nbl/builtin/hlsl/bda/__ptr.hlsl

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
22
// This file is part of the "Nabla Engine".
33
// For conditions of distribution and use, see copyright notice in nabla.h
4-
54
#include "nbl/builtin/hlsl/type_traits.hlsl"
65
#include "nbl/builtin/hlsl/bda/__ref.hlsl"
76

@@ -17,32 +16,63 @@ namespace bda
1716
template<typename T>
1817
struct __ptr
1918
{
20-
using this_t = __ptr <T>;
21-
uint64_t addr;
19+
using this_t = __ptr<T>;
20+
uint32_t2 addr;
2221

23-
static this_t create(const uint64_t _addr)
22+
static this_t create(const uint32_t2 _addr)
2423
{
2524
this_t retval;
2625
retval.addr = _addr;
2726
return retval;
2827
}
2928

29+
// in non-64bit mode we only support "small" arithmetic on pointers (just offsets no arithmetic on pointers)
30+
#if 0 // TODO: @Przemog1
31+
__ptr operator+(uint32_t i)
32+
{
33+
i *= sizeof(T);
34+
uint32_t2 newAddr = addr;
35+
uint32_t2 diff = spirv::OpIAddCarry(addr[0],i);
36+
newAddr[0] = diff[0];
37+
newAddr[1] += diff[1];
38+
return __ptr::create(newAddr);
39+
}
40+
__ptr operator-(uint32_t i)
41+
{
42+
i *= sizeof(T);
43+
uint32_t2 newAddr = addr;
44+
uint32_t2 diff = spirv::OpISubBorrow(addr[0],i);
45+
newAddr[0] = diff[0];
46+
newAddr[1] -= diff[1];
47+
return __ptr::create(newAddr);
48+
}
49+
#endif
50+
3051
template< uint64_t alignment=alignment_of_v<T> >
3152
__ref<T,alignment,false> deref()
3253
{
3354
// TODO: assert(addr&uint64_t(alignment-1)==0);
34-
using retval_t = __ref < T, alignment, false>;
35-
retval_t retval;
36-
retval.__init(addr);
55+
__ref<T,alignment,false> retval;
56+
retval.__init(spirv::bitcast<__spv_ptr_t<T>,uint32_t2>(addr));
3757
return retval;
3858
}
3959

40-
__ptr operator +(int64_t i) {
41-
return __ptr::create(addr + sizeof(T) * i);
60+
//! Dont use these, to avoid emitting shaderUint64 capability when compiling for crappy mobile GPUs
61+
static this_t create(const uint64_t _addr)
62+
{
63+
this_t retval;
64+
retval.addr = spirv::bitcast<uint32_t2>(_addr);
65+
return retval;
4266
}
43-
44-
__ptr operator-(int64_t i) {
45-
return __ptr::create(addr - sizeof(T) * i);
67+
__ptr operator+(int64_t i)
68+
{
69+
i *= sizeof(T);
70+
return __ptr::create(spirv::bitcast<uint64_t>(addr) + i);
71+
}
72+
__ptr operator-(int64_t i)
73+
{
74+
i *= sizeof(T);
75+
return __ptr::create(spirv::bitcast<uint64_t>(addr) - i);
4676
}
4777
};
4878

include/nbl/builtin/hlsl/bda/__ref.hlsl

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,23 @@ namespace hlsl
1212
{
1313
namespace bda
1414
{
15-
template<typename T>
16-
using __spv_ptr_t __NBL_CAPABILITY_PhysicalStorageBufferAddresses = spirv::pointer_t<spv::StorageClassPhysicalStorageBuffer,T>;
1715

18-
template<typename T>
19-
struct __ptr;
20-
21-
// TODO: refactor this in terms of `nbl::hlsl::` when they fix the composite struct inline SPIR-V BDA issue
2216
template<typename T, uint32_t alignment, bool _restrict>
23-
struct __base_ref
17+
struct __base_ref;
18+
template<typename T, uint32_t alignment>
19+
struct __base_ref<T,alignment,false>
2420
{
25-
// TODO:
26-
// static_assert(alignment>=alignof(T));
27-
28-
using spv_ptr_t = uint64_t;
29-
spv_ptr_t ptr;
21+
[[vk::ext_decorate(spv::DecorationAliasedPointer)]] spirv::bda_pointer_t<T> ptr;
3022

31-
__spv_ptr_t<T> __get_spv_ptr()
23+
void __init(const spirv::bda_pointer_t<T> _ptr)
3224
{
33-
return spirv::bitcast < __spv_ptr_t<T> > (ptr);
25+
ptr = _ptr;
3426
}
3527

36-
// TODO: Would like to use `spv_ptr_t` or OpAccessChain result instead of `uint64_t`
37-
void __init(const spv_ptr_t _ptr)
28+
spirv::bda_pointer_t<T> __get_spv_ptr()
3829
{
39-
ptr = _ptr;
30+
// BUG: if I don't launder the pointer through this I get ""
31+
return spirv::bitcast<spirv::bda_pointer_t<T> >(spirv::bitcast<uint32_t2>(ptr));
4032
}
4133

4234
T load()
@@ -46,22 +38,47 @@ struct __base_ref
4638

4739
void store(const T val)
4840
{
49-
spirv::store<T,alignment>(__get_spv_ptr(),val);
41+
spirv::store<T,alignment>(__get_spv_ptr(), val);
5042
}
5143
};
52-
53-
template<typename T, uint32_t alignment=alignment_of_v<T>, bool _restrict = false>
54-
struct __ref : __base_ref<T,alignment,_restrict>
44+
template<typename T, uint32_t alignment>
45+
struct __base_ref<T,alignment,true>
5546
{
56-
using base_t = __base_ref < T, alignment, _restrict>;
57-
using this_t = __ref < T, alignment, _restrict>;
47+
[[vk::ext_decorate(spv::DecorationRestrictPointer)]] spirv::bda_pointer_t<T> ptr;
5848

59-
__spv_ptr_t<T> get_ptr()
49+
void __init(const spirv::bda_pointer_t<T> _ptr)
6050
{
61-
return base_t::__get_spv_ptr();
51+
ptr = _ptr;
52+
}
53+
54+
spirv::bda_pointer_t<T> __get_spv_ptr()
55+
{
56+
// BUG: if I don't launder the pointer through this I get ""
57+
return spirv::bitcast<spirv::bda_pointer_t<T> >(spirv::bitcast<uint32_t2>(ptr));
58+
}
59+
60+
T load()
61+
{
62+
return spirv::load<T,alignment>(__get_spv_ptr() );
63+
}
64+
65+
void store(const T val)
66+
{
67+
spirv::store<T,alignment>(__get_spv_ptr(), val);
6268
}
6369
};
70+
71+
// TODO: I wish HLSL had some things like C++ which would allow you to make a "stack only"/non-storable type
72+
template<typename T, uint32_t alignment=alignment_of_v<T>, bool _restrict=false>
73+
struct __ref : __base_ref<T,alignment,_restrict>
74+
{
75+
using base_t = __base_ref< T,alignment,_restrict>;
76+
using this_t = __ref<T,alignment,_restrict>;
77+
};
6478
}
6579
}
6680
}
81+
82+
// time for some macros!
83+
// Sequence of (variableName,Type)
6784
#endif

include/nbl/builtin/hlsl/spirv_intrinsics/core.hlsl

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace hlsl
2929
// TODO: some poor soul needs to study rest of https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_capability
3030
#define __NBL_CAPABILITY_ShaderLayer [[vk::ext_capability(spv::CapabilityShaderLayer)]]
3131
#define __NBL_CAPABILITY_ShaderViewportIndex [[vk::ext_capability(spv::CapabilityShaderViewportIndex)]]
32+
// there's a whole lot more of them
3233

3334
#else
3435

@@ -44,6 +45,10 @@ namespace hlsl
4445
#define __NBL_SPIRV_SUPERSET_1_6__
4546

4647
// 1.6 core caps
48+
// UniformDecoration
49+
// Demote to helper invocation
50+
// Some integer dot product stuff
51+
//
4752

4853
#else
4954

@@ -87,12 +92,25 @@ template<uint32_t StorageClass, typename T>
8792
using pointer_t = vk::SpirvOpaqueType<spv::OpTypePointer,vk::Literal<vk::integral_constant<uint32_t,StorageClass> >,T>;
8893

8994
//! General Operations
95+
96+
//
97+
template<typename M, uint32_t StorageClass, typename T>
98+
[[vk::ext_instruction(spv::OpAccessChain)]]
99+
pointer_t<StorageClass,M> accessChain(pointer_t<StorageClass,T> v, int32_t index);
90100

91101
// The holy operation that makes addrof possible
92102
template<uint32_t StorageClass, typename T>
93103
[[vk::ext_instruction(spv::OpCopyObject)]]
94104
pointer_t<StorageClass,T> copyObject([[vk::ext_reference]] T v);
95105

106+
// unfortunately without reflection we can't validate that objects "logically match" in a concept
107+
template<typename T, typename U>
108+
[[vk::ext_instruction(spv::OpCopyLogical)]]
109+
enable_if_t<!is_same_v<T,U>,T> copyLogical([[vk::ext_reference]] U v);
110+
template<typename T, typename Ptr_U>
111+
[[vk::ext_instruction(spv::OpCopyLogical)]]
112+
enable_if_t<is_spirv_type_v<Ptr_U>/* && !is_same_v<T,U>*/,T> copyLogical(Ptr_U v);
113+
96114
// Here's the thing with atomics, it's not only the data type that dictates whether you can do an atomic or not.
97115
// It's the storage class that has the most effect (shared vs storage vs image) and we can't check that easily
98116
template<typename T> // integers operate on 2s complement so same op for signed and unsigned
@@ -204,10 +222,14 @@ template<typename T, typename Ptr_T> // DXC Workaround
204222
enable_if_t<is_spirv_type_v<Ptr_T>, T> atomicCompareExchange(Ptr_T ptr, uint32_t memoryScope, uint32_t memSemanticsEqual, uint32_t memSemanticsUnequal, T value, T comparator);
205223

206224

225+
226+
template<typename T>
227+
using bda_pointer_t __NBL_CAPABILITY_PhysicalStorageBufferAddresses = vk::SpirvType<spv::OpTypePointer,sizeof(uint64_t),/*alignof(uint64_t)*/8,vk::Literal<vk::integral_constant<uint32_t,spv::StorageClassPhysicalStorageBuffer> >,T>;
228+
207229
template<typename T, uint32_t alignment>
208230
__NBL_CAPABILITY_PhysicalStorageBufferAddresses
209231
[[vk::ext_instruction(spv::OpLoad)]]
210-
T load(pointer_t<spv::StorageClassPhysicalStorageBuffer,T> pointer, [[vk::ext_literal]] uint32_t __aligned = /*Aligned*/0x00000002, [[vk::ext_literal]] uint32_t __alignment = alignment);
232+
T load(bda_pointer_t<T> pointer, [[vk::ext_literal]] uint32_t __aligned = /*Aligned*/0x00000002, [[vk::ext_literal]] uint32_t __alignment = alignment);
211233

212234
template<typename T, typename P>
213235
[[vk::ext_instruction(spv::OpLoad)]]
@@ -216,7 +238,7 @@ enable_if_t<is_spirv_type_v<P>,T> load(P pointer);
216238
template<typename T, uint32_t alignment>
217239
__NBL_CAPABILITY_PhysicalStorageBufferAddresses
218240
[[vk::ext_instruction(spv::OpStore)]]
219-
void store(pointer_t<spv::StorageClassPhysicalStorageBuffer,T> pointer, T obj, [[vk::ext_literal]] uint32_t __aligned = /*Aligned*/0x00000002, [[vk::ext_literal]] uint32_t __alignment = alignment);
241+
void store(bda_pointer_t<T> pointer, T obj, [[vk::ext_literal]] uint32_t __aligned = /*Aligned*/0x00000002, [[vk::ext_literal]] uint32_t __alignment = alignment);
220242

221243
template<typename T, typename P>
222244
[[vk::ext_instruction(spv::OpStore)]]
@@ -234,20 +256,22 @@ void controlBarrier(uint32_t executionScope, uint32_t memoryScope, uint32_t memo
234256
void memoryBarrier(uint32_t memoryScope, uint32_t memorySemantics);
235257

236258
// Add specializations if you need to emit a `ext_capability` (this means that the instruction needs to forward through an `impl::` struct and so on)
259+
// TODO: better constraints, one should only be able to cast fundamental types, etc. https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpBitcast
260+
#if 0
237261
template<typename T, typename U>
238262
[[vk::ext_instruction(spv::OpBitcast)]]
239263
enable_if_t<is_spirv_type_v<T> && is_spirv_type_v<U>, T> bitcast(U);
240264

241-
template<typename T>
265+
template<typename U, typename T>
242266
__NBL_CAPABILITY_PhysicalStorageBufferAddresses
243267
[[vk::ext_instruction(spv::OpBitcast)]]
244-
uint64_t bitcast(pointer_t<spv::StorageClassPhysicalStorageBuffer,T>);
268+
enable_if_t<is_same_v<U,uint64_t2>||is_same_v<U,uint32_t2>,U> bitcast(bda_pointer_t<T>);
245269

246-
template<typename T>
270+
template<typename T, typename U>
247271
__NBL_CAPABILITY_PhysicalStorageBufferAddresses
248272
[[vk::ext_instruction(spv::OpBitcast)]]
249-
pointer_t<spv::StorageClassPhysicalStorageBuffer,T> bitcast(uint64_t);
250-
273+
enable_if_t<is_same_v<U,uint64_t2>||is_same_v<U,uint32_t2>,bda_pointer_t<T> > bitcast(U);
274+
#endif
251275
template<class T, class U>
252276
[[vk::ext_instruction(spv::OpBitcast)]]
253277
T bitcast(U);

include/nbl/builtin/hlsl/type_traits.hlsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ struct is_signed : bool_constant<
294294

295295
}
296296

297+
// TODO: struct & trait is named wrong
297298
template<class T>
298299
struct is_spirv_type : false_type {};
299300
template<class T, class Storage>

0 commit comments

Comments
 (0)