yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
e0c20a076
master
1//TEST_CATEGORY(wave, compute) 2//TEST:COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -shaderobj -emit-spirv-directly 3//TEST:COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -shaderobj -emit-spirv-via-glsl 4//TEST:COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-cuda -capability cuda_sm_7_0 -compute -shaderobj 5//TEST:COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -shaderobj -emit-spirv-directly -xslang -DUSE_GLSL_SYNTAX -allow-glsl 6 7//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer 8RWStructuredBuffer<uint> outputBuffer; 9 10#if defined(USE_GLSL_SYNTAX) 11#define __partitionedInclusiveMax subgroupPartitionedInclusiveMaxNV 12#define __partitionedExclusiveMax subgroupPartitionedExclusiveMaxNV 13#else 14#define __partitionedInclusiveMax WaveMultiPrefixInclusiveMax 15#define __partitionedExclusiveMax WaveMultiPrefixExclusiveMax 16#endif 17 18static bool isFirstInPartition = false; 19static uint gSmaller = 0; 20static uint gLarger = 0; 21static uint gMaxValue = 0; 22 23__generic<T : __BuiltinArithmeticType> 24bool test1MinMax(uint4 mask) 25{ 26 let smaller = T(gSmaller); 27 let maxValue = T(gMaxValue); 28 29 // The larger values are set to be the last in the partition, exclusive variants will never get these values. 30 bool exclusiveRes = true 31 & (__partitionedExclusiveMax(maxValue, mask) == smaller) 32 ; 33 // Do not check exclusive prefix for the first invocation in partition as their values(identity values) depend on the builtin type `T`. It would be 34 // nice to have something like T::min or T::max. 35 if (isFirstInPartition) 36 { 37 exclusiveRes = true; 38 } 39 40 return true 41 & (__partitionedInclusiveMax(maxValue, mask) == maxValue) 42 & exclusiveRes 43 ; 44} 45 46__generic<T : __BuiltinArithmeticType, let N : int> 47bool testVMinMax(uint4 mask) { 48 typealias GVec = vector<T, N>; 49 50 let smaller = GVec(T(gSmaller)); 51 let maxValue = GVec(T(gMaxValue)); 52 53 // The larger values are set to be the last in the partition, exclusive variants will never get these values. 54 bool exclusiveRes = true 55 & all(__partitionedExclusiveMax(maxValue, mask) == smaller) 56 ; 57 // Do not check exclusive prefix for the first invocation in partition as their values(identity values) depend on the builtin type `T`. It would be 58 // nice to have something like T::min or T::max. 59 if (isFirstInPartition) 60 { 61 exclusiveRes = true; 62 } 63 64 return true 65 & all(__partitionedInclusiveMax(maxValue, mask) == maxValue) 66 & exclusiveRes; 67 ; 68} 69 70bool testMinMax(uint4 mask) 71{ 72 return true 73 & test1MinMax<int>(mask) 74 & testVMinMax<int, 2>(mask) 75 & testVMinMax<int, 3>(mask) 76 & testVMinMax<int, 4>(mask) 77 & test1MinMax<uint>(mask) 78 & testVMinMax<uint, 2>(mask) 79 & testVMinMax<uint, 3>(mask) 80 & testVMinMax<uint, 4>(mask) 81 & test1MinMax<float>(mask) 82 & testVMinMax<float, 2>(mask) 83 & testVMinMax<float, 3>(mask) 84 & testVMinMax<float, 4>(mask) 85 & test1MinMax<double>(mask) 86 & testVMinMax<double, 2>(mask) 87 & testVMinMax<double, 3>(mask) 88 & testVMinMax<double, 4>(mask) 89 & test1MinMax<int8_t>(mask) 90 & testVMinMax<int8_t, 2>(mask) 91 & testVMinMax<int8_t, 3>(mask) 92 & testVMinMax<int8_t, 4>(mask) 93 & test1MinMax<int16_t>(mask) 94 & testVMinMax<int16_t, 2>(mask) 95 & testVMinMax<int16_t, 3>(mask) 96 & testVMinMax<int16_t, 4>(mask) 97 & test1MinMax<int64_t>(mask) 98 & testVMinMax<int64_t, 2>(mask) 99 & testVMinMax<int64_t, 3>(mask) 100 & testVMinMax<int64_t, 4>(mask) 101 & test1MinMax<uint8_t>(mask) 102 & testVMinMax<uint8_t, 2>(mask) 103 & testVMinMax<uint8_t, 3>(mask) 104 & testVMinMax<uint8_t, 4>(mask) 105 & test1MinMax<uint16_t>(mask) 106 & testVMinMax<uint16_t, 2>(mask) 107 & testVMinMax<uint16_t, 3>(mask) 108 & testVMinMax<uint16_t, 4>(mask) 109 & test1MinMax<uint64_t>(mask) 110 & testVMinMax<uint64_t, 2>(mask) 111 & testVMinMax<uint64_t, 3>(mask) 112 & testVMinMax<uint64_t, 4>(mask) 113 & test1MinMax<half>(mask) 114 & testVMinMax<half, 2>(mask) 115 & testVMinMax<half, 3>(mask) 116 & testVMinMax<half, 4>(mask) 117 ; 118} 119 120[numthreads(32, 1, 1)] 121[shader("compute")] 122[MaximallyReconverges] 123void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) 124{ 125 let index = dispatchThreadID.x; 126 127 // Split into two groups, first group has 15 invocations/lanes and second group has 17. 128 let isSecondGroup = index >= 15; 129 uint4 mask = isSecondGroup ? uint4(0xFFFF8000, 0, 0, 0) : uint4(0x0007FFF, 0, 0, 0); 130 131 isFirstInPartition = (index == 0) || (index == 15); 132 let isLastInPartition = (index == 14) || (index == 31); 133 134 gSmaller = isSecondGroup ? 2 : 0; 135 gLarger = isSecondGroup ? 3 : 1; 136 gMaxValue = isLastInPartition ? gLarger : gSmaller; 137 138 bool result = true 139 & testMinMax(mask) 140 ; 141 142 // CHECK-COUNT-32: 1 143 outputBuffer[index] = uint(result); 144}