Repository navigation
Device-wide chained scan with lookback #1086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
007f23e
9604ca6
4192826
b132a2e
b46cad2
59219c5
a056aeb
12b2d9b
068776e
747d35b
972a8fb
9085b5d
3a59e93
25e2d01
ba9e151
dd61813
02d6966
833081c
e5153a9
fbf4b57
c5b3031
12a8f56
f1ad2fa
dc7bfa6
a94a8ca
ad803f3
ba1466e
b07782f
4cb1b2a
b9d550f
f7d10b0
8810a06
1ea808d
42c8a7d
c8c42e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| #ifndef _NBL_BUILTIN_HLSL_CONCEPTS_ACCESSORS_DEVICE_ARITHMETIC_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_CONCEPTS_ACCESSORS_DEVICE_ARITHMETIC_INCLUDED_ | ||
|
|
||
| #include "nbl/builtin/hlsl/concepts/accessors/generic_shared_data.hlsl" | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace scan | ||
| { | ||
|
|
||
| #define NBL_CONCEPT_NAME GenericAtomicAccessor | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (T)(V) | ||
| #define NBL_CONCEPT_PARAM_0 (accessor, T) | ||
| #define NBL_CONCEPT_PARAM_1 (val, V) | ||
| #define NBL_CONCEPT_PARAM_2 (index, uint64_t) | ||
| NBL_CONCEPT_BEGIN(3) | ||
| #define accessor NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define val NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| #define index NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::accessors::GenericDataAccessor, T, V, uint64_t)) | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.atomicStore(index, val)), is_same_v, void)) | ||
| ); | ||
| #undef val | ||
| #undef index | ||
| #undef accessor | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| #define NBL_CONCEPT_NAME DeviceReductionsAccessor | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (T)(V) | ||
| #define NBL_CONCEPT_PARAM_0 (accessor, T) | ||
| #define NBL_CONCEPT_PARAM_1 (val, V) | ||
| #define NBL_CONCEPT_PARAM_2 (index, uint64_t) | ||
| NBL_CONCEPT_BEGIN(3) | ||
| #define accessor NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define val NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| #define index NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(GenericAtomicAccessor, T, V)) | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.atomicMax(index, val)), is_same_v, V)) | ||
| ); | ||
| #undef val | ||
| #undef index | ||
| #undef accessor | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| #define NBL_CONCEPT_NAME GenericAtomicArithmeticAccessor | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (T) | ||
| #define NBL_CONCEPT_PARAM_0 (accessor, T) | ||
| #define NBL_CONCEPT_PARAM_1 (val, uint32_t) | ||
| #define NBL_CONCEPT_PARAM_2 (index, uint64_t) | ||
| NBL_CONCEPT_BEGIN(3) | ||
| #define accessor NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define val NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| #define index NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((accessor.atomicAdd(index, val)), is_same_v, uint32_t)) | ||
| ); | ||
| #undef val | ||
| #undef index | ||
| #undef accessor | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,11 @@ namespace nbl | |
| { | ||
| namespace hlsl | ||
| { | ||
| // TODO: rename this namespace to `glsl_compat` | ||
| // The functions in this namespace are meant for porting GLSL shaders with minimal changes. | ||
| // Many of them are also handy utilities (default scopes and memory semantics, signed/unsigned/float dispatch, 16-bit emulation, | ||
| // a C++ path) and get called all over the codebase because they are easier to use than the raw `spirv::` intrinsics. | ||
| // Avoid calling them from code that isn't a GLSL port; those utilities need a home outside the `glsl` namespace. | ||
| namespace glsl | ||
| { | ||
|
|
||
|
|
@@ -125,16 +130,6 @@ enable_if_t<spirv::is_pointer_v<Ptr_T>, T> atomicXor(Ptr_T ptr, T value) | |
| { | ||
| return spirv::atomicXor<T, Ptr_T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
| /* TODO: @Hazardu struct dispatchers like for `bitfieldExtract` | ||
| template<typename T> | ||
| T atomicMin(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| } | ||
| template<typename T> | ||
| T atomicMax(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| } | ||
| */ | ||
| // reference form: `ptr` is the variable itself, e.g. `buf[i]`, `bufferPtr.Get().member`, or a groupshared variable with `T` given explicitly | ||
| template<typename T> | ||
| T atomicExchange(NBL_REF_ARG(T) ptr, T value) | ||
|
|
@@ -160,6 +155,100 @@ enable_if_t<spirv::is_pointer_v<Ptr_T>, T> atomicCompSwap(Ptr_T ptr, T comparato | |
| return spirv::atomicCompareExchange<T, Ptr_T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, spv::MemorySemanticsMaskNone, value, comparator); | ||
| } | ||
|
|
||
| namespace impl | ||
| { | ||
| template<typename T NBL_STRUCT_CONSTRAINABLE> | ||
| struct atomicMin; | ||
|
|
||
| template<typename T> | ||
| NBL_PARTIAL_REQ_TOP(concepts::SignedIntegral<T>) | ||
| struct atomicMin<T NBL_PARTIAL_REQ_BOT(concepts::SignedIntegral<T>) > | ||
| { | ||
| static T __call(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return spirv::atomicSMin<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
|
|
||
| template<typename Ptr_T> // DXC Workaround | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's best to say exactly what dxc issue we're working around and be more detailed in the comments. in case they fix it and we can upgrade our code. I have a question though. Side note:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because in C++20 you need the requires clause on the top, but Thats the convention we already chose and if we were to change it we'd have to change a lot of other code as well.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
you want to be forward compatible with C++20, because HLSL is going that way, also it keeps the code easy to port to CUDA and SYCL later on.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes @keptsecret please cite/link the DXC issue in the comments for stuff like that (git commit message too) |
||
| static T __call(Ptr_T ptr, T value) | ||
| { | ||
| return spirv::atomicSMin<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
| }; | ||
|
|
||
| template<typename T> | ||
| NBL_PARTIAL_REQ_TOP(concepts::UnsignedIntegral<T>) | ||
| struct atomicMin<T NBL_PARTIAL_REQ_BOT(concepts::UnsignedIntegral<T>) > | ||
| { | ||
| static T __call(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return spirv::atomicUMin<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
|
|
||
| template<typename Ptr_T> // DXC Workaround | ||
| static T __call(Ptr_T ptr, T value) | ||
| { | ||
| return spirv::atomicUMin<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
| }; | ||
|
|
||
| template<typename T NBL_STRUCT_CONSTRAINABLE> | ||
| struct atomicMax; | ||
|
|
||
| template<typename T> | ||
| NBL_PARTIAL_REQ_TOP(concepts::SignedIntegral<T>) | ||
| struct atomicMax<T NBL_PARTIAL_REQ_BOT(concepts::SignedIntegral<T>) > | ||
| { | ||
| static T __call(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return spirv::atomicSMax<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
|
|
||
| template<typename Ptr_T> // DXC Workaround | ||
| static T __call(Ptr_T ptr, T value) | ||
| { | ||
| return spirv::atomicSMax<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
| }; | ||
|
|
||
| template<typename T> | ||
| NBL_PARTIAL_REQ_TOP(concepts::UnsignedIntegral<T>) | ||
| struct atomicMax<T NBL_PARTIAL_REQ_BOT(concepts::UnsignedIntegral<T>) > | ||
| { | ||
| static T __call(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return spirv::atomicUMax<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
|
|
||
| template<typename Ptr_T> // DXC Workaround | ||
| static T __call(Ptr_T ptr, T value) | ||
| { | ||
| return spirv::atomicUMax<T>(ptr, spv::ScopeDevice, spv::MemorySemanticsMaskNone, value); | ||
| } | ||
| }; | ||
| } | ||
|
Comment on lines
+158
to
+229
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we actually have a huge problem here and I think this is why I didn't pour that much effort into the GLSL compat functions
Ideally none of our code should be using the GLSL atomics because they're so bad and imprecise
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This atm just matches the memory semantics of the prior atomics.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes let's use spirv ones directly and avoid these glsl compat function as much as possible. |
||
|
|
||
| template<typename T> | ||
| T atomicMin(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return impl::atomicMin<T>::__call(ptr, value); | ||
| } | ||
| template<typename T, typename Ptr_T> // DXC Workaround | ||
| enable_if_t<spirv::is_pointer_v<Ptr_T>, T> atomicMin(Ptr_T ptr, T value) | ||
| { | ||
| return impl::atomicMin<T>::template __call<Ptr_T>(ptr, value); | ||
| } | ||
| template<typename T> | ||
| T atomicMax(NBL_REF_ARG(T) ptr, T value) | ||
| { | ||
| return impl::atomicMax<T>::__call(ptr, value); | ||
| } | ||
| template<typename T, typename Ptr_T> // DXC Workaround | ||
| enable_if_t<spirv::is_pointer_v<Ptr_T>, T> atomicMax(Ptr_T ptr, T value) | ||
| { | ||
| return impl::atomicMax<T>::template __call<Ptr_T>(ptr, value); | ||
| } | ||
|
|
||
| /** | ||
| * GLSL extended math | ||
| */ | ||
|
|
@@ -189,7 +278,11 @@ uint32_t gl_InstanceIndex() {return spirv::InstanceIndex;} | |
|
|
||
| // TODO: Extemely annoying that HLSL doesn't have references, so we can't transparently alias the variables as `const&` :( | ||
| uint32_t3 gl_NumWorkGroups() {return spirv::NumWorkGroups;} | ||
| // TODO: DXC BUG prevents us from defining this! | ||
| // Not a DXC bug: SPIR-V only lets a shader declare its workgroup size, there is nothing to read back. | ||
| // `[numthreads]` emits the `LocalSize` execution mode, whose operands are literals that no instruction can reference. | ||
| // `LocalSizeId` and the `WorkgroupSize` builtin take ids instead, but those must be constants (`WorkgroupSize` on an input | ||
| // variable is invalid), so "reading" them just means reusing the constant that declared the size in the first place. | ||
| // Hence the user defines this, returning the same compile-time constant they pass to `[numthreads]`. | ||
| uint32_t3 gl_WorkGroupSize(); | ||
| uint32_t3 gl_WorkGroupID() {return spirv::WorkgroupId;} | ||
| uint32_t3 gl_LocalInvocationID() {return spirv::LocalInvocationId;} | ||
|
|
@@ -298,6 +391,8 @@ struct bitfieldExtract<T NBL_PARTIAL_REQ_BOT(concepts::UnsignedIntegral<typename | |
| }; | ||
| } | ||
|
|
||
| // TODO: `bitfieldInsert` and `bitfieldExtract` are used as general utilities outside GLSL ports (16-bit emulation, C++ path), | ||
| // they need a home outside the `glsl` namespace | ||
| template<typename T> | ||
| T bitfieldInsert(T base, T insert, uint32_t offset, uint32_t bits) | ||
| { | ||
|
|
@@ -413,6 +508,7 @@ struct notEqual_helper<Vectorial NBL_PARTIAL_REQ_BOT(concepts::Vectorial<Vectori | |
| #endif | ||
| } | ||
|
|
||
| // TODO: `equal` and `notEqual` are used as general utilities outside GLSL ports (C++ path), they need a home outside the `glsl` namespace | ||
| template<typename T> | ||
| inline vector<bool,vector_traits<T>::Dimension> equal(NBL_CONST_REF_ARG(T) x, NBL_CONST_REF_ARG(T) y) | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we generalize more and hoist it out into a
GenericAtomicAccessor(no arithmetic)