-
Notifications
You must be signed in to change notification settings - Fork 18
Chained scan unit test #287
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
6fd27d7
137ed56
0e0ad6c
6031683
15cf7db
69036ae
2836646
0990b17
5ac0f19
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,14 @@ | ||
| include(common) | ||
|
|
||
| nbl_create_executable_project("" "" "" "") | ||
|
|
||
| NBL_CREATE_RESOURCE_ARCHIVE( | ||
| NAMESPACE nbl::this_example::builtin | ||
| TARGET ${EXECUTABLE_NAME}_builtins | ||
| LINK_TO ${EXECUTABLE_NAME} | ||
| BIND app_resources | ||
| BUILTINS | ||
| common.hlsl | ||
| shaderCommon.hlsl | ||
| testGlobal.comp.hlsl | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| #include "nbl/builtin/hlsl/cpp_compat.hlsl" | ||
| #include "nbl/builtin/hlsl/functional.hlsl" | ||
|
|
||
| struct PushConstantData | ||
| { | ||
| uint64_t pInputBuf; | ||
| uint64_t pOutputBuf[8]; | ||
| uint64_t pReduceBuf; | ||
| uint64_t pWgCounterBuf; | ||
| }; | ||
|
|
||
| namespace arithmetic | ||
| { | ||
| // Thanks to our unified HLSL/C++ STD lib we're able to remove a whole load of code | ||
| template<typename T> | ||
| struct bit_and : nbl::hlsl::bit_and<T> | ||
| { | ||
| using base_t = nbl::hlsl::bit_and<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 0; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "bit_and"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct bit_or : nbl::hlsl::bit_or<T> | ||
| { | ||
| using base_t = nbl::hlsl::bit_or<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 1; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "bit_xor"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct bit_xor : nbl::hlsl::bit_xor<T> | ||
| { | ||
| using base_t = nbl::hlsl::bit_xor<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 2; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "bit_or"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct plus : nbl::hlsl::plus<T> | ||
| { | ||
| using base_t = nbl::hlsl::plus<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 3; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "plus"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct multiplies : nbl::hlsl::multiplies<T> | ||
| { | ||
| using base_t = nbl::hlsl::multiplies<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 4; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "multiplies"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct minimum : nbl::hlsl::minimum<T> | ||
| { | ||
| using base_t = nbl::hlsl::minimum<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 5; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "minimum"; | ||
| #endif | ||
| }; | ||
| template<typename T> | ||
| struct maximum : nbl::hlsl::maximum<T> | ||
| { | ||
| using base_t = nbl::hlsl::maximum<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 6; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "maximum"; | ||
| #endif | ||
| }; | ||
|
|
||
| template<typename T> | ||
| struct ballot : nbl::hlsl::plus<T> | ||
| { | ||
| using base_t = nbl::hlsl::plus<T>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE uint16_t BindingIndex = 7; | ||
| #ifndef __HLSL_VERSION | ||
| static inline constexpr const char* name = "bitcount"; | ||
| #endif | ||
| }; | ||
| } | ||
|
|
||
| #include "nbl/builtin/hlsl/glsl_compat/subgroup_basic.hlsl" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #include "app_resources/common.hlsl" | ||
|
|
||
| using namespace nbl; | ||
| using namespace hlsl; | ||
|
|
||
| [[vk::push_constant]] PushConstantData pc; | ||
|
|
||
| struct device_capabilities | ||
| { | ||
| #ifdef TEST_NATIVE | ||
| NBL_CONSTEXPR_STATIC_INLINE bool shaderSubgroupArithmetic = true; | ||
| #else | ||
| NBL_CONSTEXPR_STATIC_INLINE bool shaderSubgroupArithmetic = false; | ||
| #endif | ||
| }; | ||
|
|
||
| #ifndef OPERATION | ||
| #error "Define OPERATION!" | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| #pragma shader_stage(compute) | ||
|
|
||
| #include "nbl/builtin/hlsl/glsl_compat/core.hlsl" | ||
| #include "nbl/builtin/hlsl/glsl_compat/subgroup_basic.hlsl" | ||
| #include "nbl/builtin/hlsl/subgroup2/arithmetic_portability.hlsl" | ||
|
|
||
| #include "nbl/builtin/hlsl/bda/legacy_bda_accessor.hlsl" | ||
| #include "nbl/builtin/hlsl/scan/chained_scan.hlsl" | ||
|
|
||
| using config_t = WORKGROUP_CONFIG_T; | ||
|
|
||
| #include "app_resources/shaderCommon.hlsl" | ||
|
|
||
| typedef vector<uint32_t, config_t::ItemsPerInvocation_0> type_t; | ||
|
|
||
| groupshared uint32_t scratch[mpl::max_v<int16_t,config_t::SharedScratchElementCount,1>]; | ||
|
|
||
| struct ScratchProxy | ||
| { | ||
| template<typename AccessType, typename IndexType> | ||
| void get(const uint32_t ix, NBL_REF_ARG(AccessType) value) | ||
| { | ||
| value = scratch[ix]; | ||
| } | ||
| template<typename AccessType, typename IndexType> | ||
| void set(const uint32_t ix, const AccessType value) | ||
| { | ||
| scratch[ix] = value; | ||
|
Comment on lines
+23
to
+28
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. btw if you want these to be visible to other invocations under Vulkan memory model, you might want to use SPIR-V OpLoad |
||
| } | ||
|
|
||
| uint32_t atomicOr(const uint32_t ix, const uint32_t value) | ||
| { | ||
| return glsl::atomicOr(scratch[ix],value); | ||
| } | ||
|
|
||
| void workgroupExecutionAndMemoryBarrier() | ||
| { | ||
| glsl::barrier(); | ||
| } | ||
| }; | ||
|
|
||
| template<uint16_t VirtualWorkgroupSize, uint16_t ItemsPerInvocation> | ||
| struct DataProxy | ||
| { | ||
| using dtype_t = vector<uint32_t, ItemsPerInvocation>; | ||
| // function template AccessType should be the same as dtype_t | ||
|
|
||
| static DataProxy<VirtualWorkgroupSize, ItemsPerInvocation> create(const uint64_t inputBuf, const uint64_t outputBuf) | ||
| { | ||
| DataProxy<VirtualWorkgroupSize, ItemsPerInvocation> retval; | ||
| const uint32_t workgroupOffset = glsl::gl_WorkGroupID().x * VirtualWorkgroupSize * sizeof(dtype_t); | ||
| retval.accessor = DoubleLegacyBdaAccessor<dtype_t>::create(inputBuf + workgroupOffset, outputBuf + workgroupOffset); | ||
| retval.inputAddress = inputBuf; | ||
| retval.outputAddress = outputBuf; | ||
| return retval; | ||
| } | ||
|
|
||
| void initAtWorkgroupID(const uint32_t workgroupID) | ||
| { | ||
| const uint32_t workgroupOffset = workgroupID * VirtualWorkgroupSize * sizeof(dtype_t); | ||
| accessor = DoubleLegacyBdaAccessor<dtype_t>::create(inputAddress + workgroupOffset, outputAddress + workgroupOffset); | ||
| } | ||
|
|
||
| template<typename AccessType, typename IndexType> | ||
| void get(const IndexType ix, NBL_REF_ARG(AccessType) value) | ||
| { | ||
| accessor.get(ix, value); | ||
| } | ||
| template<typename AccessType, typename IndexType> | ||
| void set(const IndexType ix, const AccessType value) | ||
| { | ||
| accessor.set(ix, value); | ||
| } | ||
|
|
||
| uint64_t getInputBufAddr() | ||
| { | ||
| return inputAddress; | ||
| } | ||
| uint64_t getOutputBufAddr() | ||
| { | ||
| return outputAddress; | ||
| } | ||
|
|
||
| void workgroupExecutionAndMemoryBarrier() | ||
| { | ||
| glsl::barrier(); | ||
| //glsl::memoryBarrierShared(); implied by the above | ||
| } | ||
|
|
||
| DoubleLegacyBdaAccessor<dtype_t> accessor; | ||
| uint64_t inputAddress, outputAddress; | ||
| }; | ||
|
|
||
| template<typename T> | ||
| struct ReduceAccessor | ||
| { | ||
| using type_t = T; | ||
| static ReduceAccessor<T> create(const bda::__ptr<T> ptr) | ||
| { | ||
| ReduceAccessor<T> retval; | ||
| retval.ptr = ptr; | ||
| return retval; | ||
| } | ||
|
|
||
| template<typename AccessType, typename IndexType> | ||
| void get(const IndexType index, NBL_REF_ARG(AccessType) value) | ||
| { | ||
| bda::__ptr<T> target = ptr + index; | ||
| value = target.template deref().load(); | ||
| } | ||
| template<typename AccessType, typename IndexType> | ||
| void set(const IndexType index, const AccessType value) | ||
| { | ||
| bda::__ptr<T> target = ptr + index; | ||
| return target.template deref().store(value); | ||
|
Comment on lines
+108
to
+115
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. I think our Its only atomics where avail and vis + non-privateness is implied |
||
| } | ||
|
|
||
| T atomicMax(const uint64_t index, const T value) | ||
| { | ||
| bda::__ptr<T> target = ptr + index; | ||
| return glsl::atomicMax(target.template deref().ptr.value, value); | ||
| } | ||
| T atomicExchange(const uint64_t index, const T value) | ||
| { | ||
| bda::__ptr<T> target = ptr + index; | ||
| return glsl::atomicExchange(target.template deref().ptr.value, value); | ||
| } | ||
|
|
||
| void memoryBarrier() | ||
| { | ||
| spirv::memoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAcquireReleaseMask | spv::MemorySemanticsUniformMemoryMask); | ||
| } | ||
|
|
||
| bda::__ptr<T> ptr; | ||
| }; | ||
|
|
||
| struct WorkgroupCounter | ||
| { | ||
| static WorkgroupCounter create(const uint64_t addr) | ||
| { | ||
| WorkgroupCounter retval; | ||
| retval.ptr = bda::__ptr<uint32_t>::create(addr); | ||
| return retval; | ||
| } | ||
|
|
||
| uint32_t atomicAdd(const uint64_t index, const uint32_t value) // TODO: maybe it should be just increment | ||
| { | ||
| bda::__ptr<uint32_t> target = ptr + index; | ||
| return glsl::atomicAdd(target.template deref().ptr.value, value); | ||
| } | ||
|
|
||
| bda::__ptr<uint32_t> ptr; | ||
| }; | ||
|
|
||
| static ScratchProxy arithmeticAccessor; | ||
|
|
||
| template<class Binop, class device_capabilities> | ||
| struct operation_t | ||
| { | ||
| using binop_base_t = typename Binop::base_t; | ||
| using otype_t = typename Binop::type_t; | ||
|
|
||
| void operator()() | ||
| { | ||
| using data_proxy_t = DataProxy<config_t::VirtualWorkgroupSize,config_t::ItemsPerInvocation_0>; | ||
| data_proxy_t dataAccessor = data_proxy_t::create(pc.pInputBuf, pc.pOutputBuf[Binop::BindingIndex]); | ||
|
|
||
| using reduce_proxy_t = ReduceAccessor<otype_t>; | ||
| bda::__ptr<otype_t> ptr = bda::__ptr<otype_t>::create(pc.pReduceBuf); | ||
| reduce_proxy_t reduceAccessor = reduce_proxy_t::create(ptr); | ||
|
|
||
| WorkgroupCounter wgCounter = WorkgroupCounter::create(pc.pWgCounterBuf); | ||
|
|
||
| OPERATION<config_t,binop_base_t,device_capabilities>::template __call<data_proxy_t, ScratchProxy, reduce_proxy_t, WorkgroupCounter>(dataAccessor,arithmeticAccessor,reduceAccessor,wgCounter); | ||
| // we barrier before because we alias the accessors for Binop | ||
| arithmeticAccessor.workgroupExecutionAndMemoryBarrier(); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| template<class Binop> | ||
| static void subtest() | ||
| { | ||
| assert(glsl::gl_SubgroupSize() == config_t::SubgroupSize) | ||
|
|
||
| operation_t<Binop,device_capabilities> func; | ||
| func(); | ||
| } | ||
|
|
||
| void test() | ||
| { | ||
| // subtest<arithmetic::bit_and<uint32_t> >(); | ||
| // subtest<arithmetic::bit_xor<uint32_t> >(); | ||
| // subtest<arithmetic::bit_or<uint32_t> >(); | ||
| subtest<arithmetic::plus<uint32_t> >(); | ||
| // subtest<arithmetic::multiplies<uint32_t> >(); | ||
| // subtest<arithmetic::minimum<uint32_t> >(); | ||
| // subtest<arithmetic::maximum<uint32_t> >(); | ||
| } | ||
|
|
||
| [numthreads(config_t::WorkgroupSize,1,1)] | ||
| void main() | ||
| { | ||
| test(); | ||
| } | ||
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.
small nitpicking: If you do
{ "TEST_NATIVE", "1" }to enable this, it should be #if not #ifdefThere 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.
indeeed