public void HillisSteeleSumScanTest()
        {
            uint[] array        = new uint[ARRAY_COUNT];
            uint[] scannedArray = new uint[ARRAY_COUNT];
            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                array[i] = GenerateRandomUInt();
            }

            ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint);

            ComputeShaderUtil.InitKernels();
            HillisSteeleSumScan.InitKernels();

            cb_in.SetData(array);

            HillisSteeleSumScan hillisSteeleSumScan = new HillisSteeleSumScan(ARRAY_COUNT);

            hillisSteeleSumScan.Scan(ref cb_in);

            cb_in.GetData(scannedArray);

            // using serial inclusive sum scan method to make sure that the parallel method works
            uint sum = 0;

            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                sum += array[i];
                Assert.AreEqual(sum, scannedArray[i], i.ToString());
            }

            cb_in.Dispose();
            hillisSteeleSumScan.Dispose();
        }
        public void HillisSteeleFloat3MaxScanTest()
        {
            float3[] array        = new float3[ARRAY_COUNT];
            float3[] scannedArray = new float3[ARRAY_COUNT];
            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                array[i] = GenerateRandomFloat3();
            }

            ComputeBuffer cb_in = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_float3);

            ComputeShaderUtil.InitKernels();
            HillisSteeleFloat3MaxScan.InitKernels();

            cb_in.SetData(array);

            HillisSteeleFloat3MaxScan hillisSteeleFloat3MaxScan = new HillisSteeleFloat3MaxScan(ARRAY_COUNT);

            hillisSteeleFloat3MaxScan.Scan(ref cb_in);

            cb_in.GetData(scannedArray);

            // using serial inclusive min scan method to make sure that the parallel method works
            float3 float3Max = array[0];

            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                float3Max = math.max(float3Max, array[i]);
                Assert.AreEqual(float3Max, scannedArray[i]);
            }

            cb_in.Dispose();
            hillisSteeleFloat3MaxScan.Dispose();
        }
        /// <summary>Sorts an array of unsigned integers in parallel.</summary>
        public void Sort(int maxShiftWidth = 32)
        {
            Profiler.BeginSample("RadixSort");
            ComputeShaderUtil.ZeroOut(ref cb_sortTemp, _dataSize);
            ComputeShaderUtil.ZeroOut(ref cb_indexTemp, _dataSize);
            ComputeShaderUtil.ZeroOut(ref cb_prefixSums, _dataSize);
            ComputeShaderUtil.ZeroOut(ref cb_blockSums, _blockSumsSize);
            ComputeShaderUtil.ZeroOut(ref cb_scanBlockSums, _blockSumsSize);

            // for every 2 bits from LSB to MSB:
            // block-wise radix sort (write blocks back to global memory)
            for (int shiftWidth = 0; shiftWidth < maxShiftWidth; shiftWidth += 2)
            {
                cs_radixSort.SetInt(PropertyID.shiftWidth, shiftWidth);
                cs_radixSort.Dispatch(kn_radixSortLocal, _sortGridSize, 1, 1);

                // scan global block sum array
                ComputeShaderUtil.ZeroOut(ref cb_scanBlockSums, _blockSumsSize);
                _blellochSumScan.Scan(ref cb_blockSums, ref cb_scanBlockSums, _blockSumsSize);

                // scatter/shuffle block-wise sorted array to final positions
                cs_radixSort.Dispatch(kn_globalShuffle, _sortGridSize, 1, 1);
            }
            Profiler.EndSample();
        }
Exemple #4
0
        public void Scan(
            ref ComputeBuffer cb_in, ref ComputeBuffer cb_out,
            int dataSize, int recurseNum = 0
            )
        {
            Profiler.BeginSample("BlellochSumScan");
            int blellochGridSize = _gridSizes[recurseNum];

            ComputeBuffer cb_sumScanBlockSum = cb_sumScanBlockSums[recurseNum];

            ComputeShaderUtil.ZeroOut(ref cb_sumScanBlockSum, blellochGridSize);

            // sum scan data allocated to each block
            cs_blellochSumScan.SetInt(PropertyID.len, dataSize);
            cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_out, cb_out);
            cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_in, cb_in);
            cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_blockSums, cb_sumScanBlockSum);
            cs_blellochSumScan.Dispatch(kn_preSumScan, blellochGridSize, 1, 1);

            // sum scan total sums produced by each block
            // use basic implementation if number of total sums is <= 2 * Graphics.M_BLOCK_SZ
            // (this requires only one block to do the scan)
            if (blellochGridSize <= Graphics.S_BLOCK_SZ)
            {
                ComputeShaderUtil.ZeroOut(ref cb_dummyGrpSums, 1);

                ComputeBuffer cb_preSumScanTemp = cb_preSumScanTemps[recurseNum];
                ComputeShaderUtil.CopyBuffer(ref cb_sumScanBlockSum, ref cb_preSumScanTemp, blellochGridSize);

                cs_blellochSumScan.SetInt(PropertyID.len, blellochGridSize);
                cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_out, cb_sumScanBlockSum);
                cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_in, cb_preSumScanTemp);
                cs_blellochSumScan.SetBuffer(kn_preSumScan, BufferID.cb_blockSums, cb_dummyGrpSums);
                cs_blellochSumScan.Dispatch(kn_preSumScan, 1, 1, 1);
            }
            else // else, recurse on this same function as you'll need the full-blown scan for the block sums
            {
                ComputeBuffer cb_inBlockSum = cb_inBlockSums[recurseNum];
                ComputeShaderUtil.CopyBuffer(ref cb_sumScanBlockSum, ref cb_inBlockSum, blellochGridSize);
                Scan(ref cb_inBlockSum, ref cb_sumScanBlockSum, blellochGridSize, recurseNum + 1);
            }

            ComputeBuffer cb_addBlockSumsTemp = cb_addBlockSumsTemps[recurseNum];

            ComputeShaderUtil.CopyBuffer(ref cb_out, ref cb_addBlockSumsTemp, dataSize);
            // add each block's total sum to its scan output in order to get the final, global scanned array
            cs_blellochSumScan.SetInt(PropertyID.len, dataSize);
            cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_out, cb_out);
            cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_in, cb_addBlockSumsTemp);
            cs_blellochSumScan.SetBuffer(kn_addBlockSums, BufferID.cb_blockSums, cb_sumScanBlockSum);
            cs_blellochSumScan.Dispatch(kn_addBlockSums, blellochGridSize, 1, 1);

            Profiler.EndSample();
        }
Exemple #5
0
        public void Scan(ref ComputeBuffer cb_in)
        {
            Profiler.BeginSample("HillisSteeleFloat3MaxScan");
            cs_hillisSteeleFloat3MaxScan.SetInt(PropertyID.len, _dataSize);
            cs_hillisSteeleFloat3MaxScan.SetBuffer(kn_hillisSteeleFloat3MaxScan, BufferID.cb_in, cb_in);
            cs_hillisSteeleFloat3MaxScan.SetBuffer(kn_hillisSteeleFloat3MaxScan, BufferID.cb_prev, cb_prev);

            for (int offset = 1; offset < _dataSize; offset <<= 1)
            {
                ComputeShaderUtil.CopyBufferFloat3(ref cb_in, ref cb_prev, _dataSize);
                cs_hillisSteeleFloat3MaxScan.SetInt(PropertyID.offset, offset);
                cs_hillisSteeleFloat3MaxScan.Dispatch(kn_hillisSteeleFloat3MaxScan, _gridSize, 1, 1);
            }
            Profiler.EndSample();
        }
        public void RadixSortTest()
        {
            uint[] array       = new uint[ARRAY_COUNT];
            uint[] sortedArray = new uint[ARRAY_COUNT];
            int[]  indices     = MathUtil.GenerateSeqArray(ARRAY_COUNT);
            for (uint i = 0; i < ARRAY_COUNT; i++)
            {
                array[i] = GenerateRandomUInt();
            }

            ComputeBuffer cb_sort    = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint);
            ComputeBuffer cb_indices = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_int);

            ComputeShaderUtil.InitKernels();
            RadixSort.InitKernels();

            cb_sort.SetData(array);
            cb_indices.SetData(indices);

            RadixSort radixSort = new RadixSort(ARRAY_COUNT);

            radixSort.Setup(ref cb_sort, ref cb_indices);
            radixSort.Sort();

            cb_sort.GetData(sortedArray);
            cb_indices.GetData(indices);

            // check if sorting works
            for (int i = 0; i < ARRAY_COUNT - 1; i++)
            {
                Assert.GreaterOrEqual(sortedArray[i + 1], sortedArray[i]);
            }
            // check if indices are sorted properly
            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                Assert.AreEqual(array[indices[i]], sortedArray[i]);
            }

            cb_sort.Dispose();
            cb_indices.Dispose();
            radixSort.Dispose();
        }
        public void BlellochSumScanTest()
        {
            uint[] array        = new uint[ARRAY_COUNT];
            uint[] scannedArray = new uint[ARRAY_COUNT];
            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                array[i] = GenerateRandomUInt();
            }

            ComputeBuffer cb_in  = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint);
            ComputeBuffer cb_out = new ComputeBuffer(ARRAY_COUNT, StrideSize.s_uint);

            ComputeShaderUtil.InitKernels();
            BlellochSumScan.InitKernels();

            cb_in.SetData(array);
            ComputeShaderUtil.ZeroOut(ref cb_out, ARRAY_COUNT);

            BlellochSumScan blellochSumScan = new BlellochSumScan(ARRAY_COUNT);

            blellochSumScan.Scan(ref cb_in, ref cb_out, ARRAY_COUNT);

            cb_out.GetData(scannedArray);

            // using serial exclusive sum scan method to make sure that the parallel method works
            uint sum = 0;

            for (int i = 0; i < ARRAY_COUNT; i++)
            {
                Assert.AreEqual(sum, scannedArray[i]);
                sum += array[i];
            }

            cb_in.Dispose();
            cb_out.Dispose();
            blellochSumScan.Dispose();
        }