private T[] CreateAndCopyToDebugBuf <T>(D3D11Buffer buffer) where T : struct { var d3dDevice = this.deviceResources.D3DDevice; var d3dContext = this.deviceResources.D3DContext; var desc = buffer.Description; desc.CpuAccessOptions = D3D11CpuAccessOptions.Read; desc.Usage = D3D11Usage.Staging; desc.BindOptions = D3D11BindOptions.None; desc.MiscOptions = D3D11ResourceMiscOptions.None; //int sizeT = Marshal.SizeOf<T>(); int sizeT = Unsafe.SizeOf <T>(); int dataLength = (int)desc.ByteWidth / sizeT; var data = new T[dataLength]; using (var debugbuf = d3dDevice.CreateBuffer(desc)) { d3dContext.CopyResource(debugbuf, buffer); D3D11MappedSubResource mappedResource = d3dContext.Map(debugbuf, 0, D3D11MapCpuPermission.Read, D3D11MapOptions.None); try { //for (int i = 0; i < dataLength; i++) //{ // data[i] = Marshal.PtrToStructure<T>(mappedResource.Data + i * sizeT); //} var b = new byte[desc.ByteWidth]; Marshal.Copy(mappedResource.Data, b, 0, b.Length); IntPtr d = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); Marshal.Copy(b, 0, d, b.Length); } finally { d3dContext.Unmap(debugbuf, 0); } } return(data); }
static void GPUSort() { var d3dContext = deviceResources.D3DContext; // Upload the data d3dContext.UpdateSubresource(g_pBuffer1, 0, null, data, 0, 0); d3dContext.ComputeShaderSetConstantBuffers(0, new[] { g_pCB }); // Sort the data // First sort the rows for the levels <= to the block size for (uint level = 2; level <= BITONIC_BLOCK_SIZE; level *= 2) { GPUSortSetConstants(level, level, MATRIX_HEIGHT, MATRIX_WIDTH); // Sort the row data d3dContext.ComputeShaderSetUnorderedAccessViews(0, new[] { g_pBuffer1UAV }, new[] { 0U }); d3dContext.ComputeShaderSetShader(g_pComputeShaderBitonic, null); d3dContext.Dispatch(NUM_ELEMENTS / BITONIC_BLOCK_SIZE, 1, 1); } // Then sort the rows and columns for the levels > than the block size // Transpose. Sort the Columns. Transpose. Sort the Rows. for (uint level = (BITONIC_BLOCK_SIZE * 2); level <= NUM_ELEMENTS; level *= 2) { GPUSortSetConstants(level / BITONIC_BLOCK_SIZE, (level & ~NUM_ELEMENTS) / BITONIC_BLOCK_SIZE, MATRIX_WIDTH, MATRIX_HEIGHT); // Transpose the data from buffer 1 into buffer 2 d3dContext.ComputeShaderSetShaderResources(0, new D3D11ShaderResourceView[] { null }); d3dContext.ComputeShaderSetUnorderedAccessViews(0, new[] { g_pBuffer2UAV }, new[] { 0U }); d3dContext.ComputeShaderSetShaderResources(0, new[] { g_pBuffer1SRV }); d3dContext.ComputeShaderSetShader(g_pComputeShaderTranspose, null); d3dContext.Dispatch(MATRIX_WIDTH / TRANSPOSE_BLOCK_SIZE, MATRIX_HEIGHT / TRANSPOSE_BLOCK_SIZE, 1); // Sort the transposed column data d3dContext.ComputeShaderSetShader(g_pComputeShaderBitonic, null); d3dContext.Dispatch(NUM_ELEMENTS / BITONIC_BLOCK_SIZE, 1, 1); GPUSortSetConstants(BITONIC_BLOCK_SIZE, level, MATRIX_HEIGHT, MATRIX_WIDTH); // Transpose the data from buffer 2 back into buffer 1 d3dContext.ComputeShaderSetShaderResources(0, new D3D11ShaderResourceView[] { null }); d3dContext.ComputeShaderSetUnorderedAccessViews(0, new[] { g_pBuffer1UAV }, new[] { 0U }); d3dContext.ComputeShaderSetShaderResources(0, new[] { g_pBuffer2SRV }); d3dContext.ComputeShaderSetShader(g_pComputeShaderTranspose, null); d3dContext.Dispatch(MATRIX_HEIGHT / TRANSPOSE_BLOCK_SIZE, MATRIX_WIDTH / TRANSPOSE_BLOCK_SIZE, 1); // Sort the row data d3dContext.ComputeShaderSetShader(g_pComputeShaderBitonic, null); d3dContext.Dispatch(NUM_ELEMENTS / BITONIC_BLOCK_SIZE, 1, 1); } // Download the data d3dContext.CopyResource(g_pReadBackBuffer, g_pBuffer1); D3D11MappedSubResource mappedResource = d3dContext.Map(g_pReadBackBuffer, 0, D3D11MapCpuPermission.Read, D3D11MapOptions.None); try { for (int i = 0; i < NUM_ELEMENTS; i++) { results[i] = (uint)Marshal.ReadInt32(mappedResource.Data + i * sizeof(uint)); } } finally { d3dContext.Unmap(g_pReadBackBuffer, 0); } }
public void PerEdgeTessellation( XMMatrix matWVP, ref D3D11Buffer ppTessedVerticesBuf, ref D3D11Buffer ppTessedIndicesBuf, out uint num_tessed_vertices, out uint num_tessed_indices) { var d3dDevice = this.deviceResources.D3DDevice; var d3dContext = this.deviceResources.D3DContext; // Update per-edge tessellation factors { EdgeFactorConstantBuffer cbCS = default; cbCS.MatWVP = matWVP; cbCS.TessEdgeLengthScale = this.m_tess_edge_len_scale; cbCS.NumTriangles = this.m_nVertices / 3; d3dContext.UpdateSubresource( this.s_pEdgeFactorCSCB, D3D11Utils.CalcSubresource(0, 0, 1), null, cbCS, EdgeFactorConstantBuffer.Size, EdgeFactorConstantBuffer.Size); this.RunComputeShader( this.s_pEdgeFactorCS, new[] { this.m_pBaseVBSRV }, null, this.s_pEdgeFactorCSCB, this.m_pEdgeFactorBufUAV, (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f), 1U, 1U); } // How many vertices/indices are needed for the tessellated mesh? { uint[] cbCS = new uint[] { this.m_nVertices / 3, 0, 0, 0 }; d3dContext.UpdateSubresource( this.s_pCSCB, D3D11Utils.CalcSubresource(0, 0, 1), null, cbCS, 4 * 4, 4 * 4); this.RunComputeShader( this.s_pNumVerticesIndicesCSs[(int)this.PartitioningMode], new[] { this.m_pEdgeFactorBufSRV }, this.s_pLookupTableCSCB, this.s_pCSCB, this.m_pScanBuf0UAV, (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f), 1U, 1U); this.s_ScanCS.Scan(d3dContext, this.m_nVertices / 3, this.m_pScanBuf0SRV, this.m_pScanBuf0UAV, this.m_pScanBuf1SRV, this.m_pScanBuf1UAV); // read back the number of vertices/indices for tessellation output D3D11Box box = default; box.Left = 4 * 2 * this.m_nVertices / 3 - 4 * 2; box.Right = 4 * 2 * this.m_nVertices / 3; box.Top = 0; box.Bottom = 1; box.Front = 0; box.Back = 1; d3dContext.CopySubresourceRegion(this.s_pCSReadBackBuf, 0, 0, 0, 0, this.m_pScanBuf0, 0, box); D3D11MappedSubResource mappedResource = d3dContext.Map(this.s_pCSReadBackBuf, 0, D3D11MapCpuPermission.Read, D3D11MapOptions.None); try { num_tessed_vertices = (uint)Marshal.ReadInt32(mappedResource.Data + 4 * 0); num_tessed_indices = (uint)Marshal.ReadInt32(mappedResource.Data + 4 * 1); } finally { d3dContext.Unmap(this.s_pCSReadBackBuf, 0); } } if (num_tessed_vertices == 0 || num_tessed_indices == 0) { return; } // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to m_pScanBuf0 if (DebugEnabled) { #pragma warning disable IDE0059 // Assignation inutile d'une valeur var p = this.CreateAndCopyToDebugBuf <(uint v, uint t)>(this.m_pScanBuf0); #pragma warning restore IDE0059 // Assignation inutile d'une valeur } // Generate buffers for scattering TriID and IndexID for both vertex data and index data, // also generate buffers for output tessellated vertex data and index data { if (this.m_pScatterVertexBuf == null || this.m_nCachedTessedVertices < num_tessed_vertices || this.m_nCachedTessedVertices > num_tessed_vertices * 2) { D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBuf); D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBufSRV); D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBufUAV); D3D11Utils.DisposeAndNull(ref ppTessedVerticesBuf); D3D11Utils.DisposeAndNull(ref this.m_pTessedVerticesBufUAV); D3D11Utils.DisposeAndNull(ref this.m_pTessedVerticesBufSRV); this.m_pScatterVertexBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc { BindOptions = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess, ByteWidth = 4 * 2 * num_tessed_vertices, StructureByteStride = 4 * 2, MiscOptions = D3D11ResourceMiscOptions.BufferStructured, Usage = D3D11Usage.Default }); this.m_pScatterVertexBufSRV = d3dDevice.CreateShaderResourceView(this.m_pScatterVertexBuf, new D3D11ShaderResourceViewDesc { ViewDimension = D3D11SrvDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferSrv { FirstElement = 0, NumElements = num_tessed_vertices } }); this.m_pScatterVertexBufUAV = d3dDevice.CreateUnorderedAccessView(this.m_pScatterVertexBuf, new D3D11UnorderedAccessViewDesc { ViewDimension = D3D11UavDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferUav { FirstElement = 0, NumElements = num_tessed_vertices } }); // generate the output tessellated vertices buffer ppTessedVerticesBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc { BindOptions = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess, ByteWidth = 4 * 3 * num_tessed_vertices, StructureByteStride = 4 * 3, MiscOptions = D3D11ResourceMiscOptions.BufferStructured, Usage = D3D11Usage.Default }); this.m_pTessedVerticesBufUAV = d3dDevice.CreateUnorderedAccessView(ppTessedVerticesBuf, new D3D11UnorderedAccessViewDesc { ViewDimension = D3D11UavDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferUav { FirstElement = 0, NumElements = num_tessed_vertices } }); this.m_pTessedVerticesBufSRV = d3dDevice.CreateShaderResourceView(ppTessedVerticesBuf, new D3D11ShaderResourceViewDesc { ViewDimension = D3D11SrvDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferSrv { FirstElement = 0, NumElements = num_tessed_vertices } }); this.m_nCachedTessedVertices = num_tessed_vertices; } if (this.m_pScatterIndexBuf == null || this.m_nCachedTessedIndices < num_tessed_indices) { D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBuf); D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBufSRV); D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBufUAV); D3D11Utils.DisposeAndNull(ref ppTessedIndicesBuf); D3D11Utils.DisposeAndNull(ref this.m_pTessedIndicesBufUAV); this.m_pScatterIndexBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc { BindOptions = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess, ByteWidth = 4 * 2 * num_tessed_indices, StructureByteStride = 4 * 2, MiscOptions = D3D11ResourceMiscOptions.BufferStructured, Usage = D3D11Usage.Default }); this.m_pScatterIndexBufSRV = d3dDevice.CreateShaderResourceView(this.m_pScatterIndexBuf, new D3D11ShaderResourceViewDesc { ViewDimension = D3D11SrvDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferSrv { FirstElement = 0, NumElements = num_tessed_indices } }); this.m_pScatterIndexBufUAV = d3dDevice.CreateUnorderedAccessView(this.m_pScatterIndexBuf, new D3D11UnorderedAccessViewDesc { ViewDimension = D3D11UavDimension.Buffer, Format = DxgiFormat.Unknown, Buffer = new D3D11BufferUav { FirstElement = 0, NumElements = num_tessed_indices } }); // generate the output tessellated indices buffer ppTessedIndicesBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc { BindOptions = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess | D3D11BindOptions.IndexBuffer, ByteWidth = 4 * num_tessed_indices, MiscOptions = D3D11ResourceMiscOptions.BufferAllowRawViews, Usage = D3D11Usage.Default }); this.m_pTessedIndicesBufUAV = d3dDevice.CreateUnorderedAccessView(ppTessedIndicesBuf, new D3D11UnorderedAccessViewDesc { ViewDimension = D3D11UavDimension.Buffer, Format = DxgiFormat.R32Typeless, Buffer = new D3D11BufferUav { FirstElement = 0, NumElements = num_tessed_indices, Options = D3D11BufferUavOptions.Raw } }); this.m_nCachedTessedIndices = num_tessed_indices; } } // Scatter TriID, IndexID { uint[] cbCS = new uint[] { this.m_nVertices / 3, 0, 0, 0 }; D3D11ShaderResourceView[] aRViews = new[] { this.m_pScanBuf0SRV }; d3dContext.UpdateSubresource( this.s_pCSCB, D3D11Utils.CalcSubresource(0, 0, 1), null, cbCS, 4 * 4, 4 * 4); // Scatter vertex TriID, IndexID this.RunComputeShader( this.s_pScatterVertexTriIDIndexIDCS, aRViews, null, this.s_pCSCB, this.m_pScatterVertexBufUAV, (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f), 1U, 1U); // Scatter index TriID, IndexID this.RunComputeShader( this.s_pScatterIndexTriIDIndexIDCS, aRViews, null, this.s_pCSCB, this.m_pScatterIndexBufUAV, (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f), 1U, 1U); } // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to m_pScatterVertexBuf if (DebugEnabled) { #pragma warning disable IDE0059 // Assignation inutile d'une valeur var p = this.CreateAndCopyToDebugBuf <(uint v, uint t)>(this.m_pScatterVertexBuf); #pragma warning restore IDE0059 // Assignation inutile d'une valeur } // Tessellate vertex { uint[] cbCS = new uint[] { num_tessed_vertices, 0, 0, 0 }; d3dContext.UpdateSubresource( this.s_pCSCB, D3D11Utils.CalcSubresource(0, 0, 1), null, cbCS, 4 * 4, 4 * 4); this.RunComputeShader( this.s_pTessVerticesCSs[(int)this.PartitioningMode], new[] { this.m_pScatterVertexBufSRV, this.m_pEdgeFactorBufSRV }, this.s_pLookupTableCSCB, this.s_pCSCB, this.m_pTessedVerticesBufUAV, (uint)Math.Ceiling(num_tessed_vertices / 128.0f), 1U, 1U); } // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to *ppTessedVerticesBuf if (DebugEnabled) { #pragma warning disable IDE0059 // Assignation inutile d'une valeur var p = this.CreateAndCopyToDebugBuf <(uint id, float u, float v)>(ppTessedVerticesBuf); #pragma warning restore IDE0059 // Assignation inutile d'une valeur } // Tessellate indices { uint[] cbCS = new uint[] { num_tessed_indices, 0, 0, 0 }; d3dContext.UpdateSubresource( this.s_pCSCB, D3D11Utils.CalcSubresource(0, 0, 1), null, cbCS, 4 * 4, 4 * 4); this.RunComputeShader( this.s_pTessIndicesCSs[(int)this.PartitioningMode], new[] { this.m_pScatterIndexBufSRV, this.m_pEdgeFactorBufSRV, this.m_pScanBuf0SRV }, this.s_pLookupTableCSCB, this.s_pCSCB, this.m_pTessedIndicesBufUAV, (uint)Math.Ceiling(num_tessed_indices / 128.0f), 1U, 1U); } // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to *ppTessedIndicesBuf if (DebugEnabled) { #pragma warning disable IDE0059 // Assignation inutile d'une valeur var p = this.CreateAndCopyToDebugBuf <int>(ppTessedIndicesBuf); #pragma warning restore IDE0059 // Assignation inutile d'une valeur } }
static void Main(string[] args) { try { Console.Write("Creating device..."); CreateComputeDevice(); Console.WriteLine("done"); Console.Write("Creating Compute Shader..."); CreateComputeShader(); Console.WriteLine("done"); Console.Write("Creating buffers and filling them with initial data..."); for (int i = 0; i < NUM_ELEMENTS; ++i) { g_vBuf0[i].i = i; g_vBuf0[i].f = (float)i; #if TEST_DOUBLE g_vBuf0[i].d = (double)i; #endif g_vBuf1[i].i = i; g_vBuf1[i].f = (float)i; #if TEST_DOUBLE g_vBuf1[i].d = (double)i; #endif } #if USE_STRUCTURED_BUFFERS g_pBuf0 = CreateStructuredBuffer(deviceResources.D3DDevice, g_vBuf0); g_pBuf1 = CreateStructuredBuffer(deviceResources.D3DDevice, g_vBuf1); g_pBufResult = CreateStructuredBuffer(deviceResources.D3DDevice, new BufType[NUM_ELEMENTS]); #else g_pBuf0 = CreateRawBuffer(deviceResources.D3DDevice, g_vBuf0); g_pBuf1 = CreateRawBuffer(deviceResources.D3DDevice, g_vBuf1); g_pBufResult = CreateRawBuffer(deviceResources.D3DDevice, new BufType[NUM_ELEMENTS]); #endif #if DEBUG g_pBuf0?.SetDebugName("Buffer0"); g_pBuf1?.SetDebugName("Buffer1"); g_pBufResult?.SetDebugName("Result"); #endif Console.WriteLine("done"); Console.Write("Creating buffer views..."); g_pBuf0SRV = CreateBufferSRV(deviceResources.D3DDevice, g_pBuf0); g_pBuf1SRV = CreateBufferSRV(deviceResources.D3DDevice, g_pBuf1); g_pBufResultUAV = CreateBufferUAV(deviceResources.D3DDevice, g_pBufResult); #if DEBUG g_pBuf0SRV?.SetDebugName("Buffer0 SRV"); g_pBuf1SRV?.SetDebugName("Buffer1 SRV"); g_pBufResultUAV?.SetDebugName("Result UAV"); #endif Console.WriteLine("done"); Console.Write("Running Compute Shader..."); RunComputeShader(deviceResources.D3DContext, g_pCS, new[] { g_pBuf0SRV, g_pBuf1SRV }, g_pBufResultUAV, NUM_ELEMENTS, 1, 1); Console.WriteLine("done"); // Read back the result from GPU, verify its correctness against result computed by CPU D3D11Buffer debugbuf = CreateAndCopyToDebugBuf(deviceResources.D3DDevice, deviceResources.D3DContext, g_pBufResult); try { D3D11MappedSubResource mappedResource = deviceResources.D3DContext.Map(debugbuf, 0, D3D11MapCpuPermission.Read, D3D11MapOptions.None); try { // Set a break point here and put down the expression "p, 1024" in your watch window to see what has been written out by our CS // This is also a common trick to debug CS programs. // Verify that if Compute Shader has done right Console.Write("Verifying against CPU result..."); bool bSuccess = true; for (int i = 0; i < NUM_ELEMENTS; ++i) { BufType p = Marshal.PtrToStructure <BufType>(mappedResource.Data + i * (int)BufType.Size); if ((p.i != g_vBuf0[i].i + g_vBuf1[i].i) || (p.f != g_vBuf0[i].f + g_vBuf1[i].f) #if TEST_DOUBLE || (p.d != g_vBuf0[i].d + g_vBuf1[i].d) #endif ) { Console.WriteLine("failure"); bSuccess = false; break; } } if (bSuccess) { Console.WriteLine("succeeded"); } } finally { deviceResources.D3DContext.Unmap(debugbuf, 0); } } finally { D3D11Utils.ReleaseAndNull(ref debugbuf); } } catch (Exception ex) { Console.WriteLine(ex); } finally { Console.Write("Cleaning up..."); CleanupResources(); Console.WriteLine("done"); } Console.ReadKey(false); }