S&box Wiki

Revision Difference

Compute_Shaders#551294

<cat>Material.ShaderBasic</cat> <title>Compute Shaders</title> # What can you do with compute shaders? You can use compute shaders to do lots of things, but their most common use is to generate textures at blazing fast speeds; here's an example that shows you how you can do that. ## Using compute shaders from C# Here's an example of creating a compute shader and populating a texture with it. ```csharp // Create a compute shader from a .shader file var computeShader = new ComputeShader( "my_compute_shader" ); // Create a texture for the compute shader to use var texture = Texture.Create( 512, 512 ) .WithUAVBinding() // Needs to have this if we're using it in a compute shader .WithFormat( ImageFormat.RGBA16161616F ) // Use whatever you need .Finish(); // Attach texture to OutputTexture attribute in shader computeShader.Attributes.Set( "OutputTexture", texture ); // Dispatch computeShader.Dispatch( texture.Width, texture.Height, 1 ); ``` ## HLSL Shader Compute shaders are HLSL like normal shaders, except everything goes in a CS block and runs a method named MainCs. Here's a really simple one that'll generate a solid pink texture: ``` MODES { Default(); } COMMON { #include "common/shared.hlsl" } CS { // Output texture RWTexture2D<float4> g_tOutput< Attribute( "OutputTexture" ); >; [numthreads(8, 8, 1)] void MainCs( uint uGroupIndex : SV_GroupIndex, uint3 vThreadId : SV_DispatchThreadID ) { g_tOutput[vThreadId.xy] = float4( 1, 0, 1, 1 ); } } ``` ⤶ ## Compute Buffers⤶ ⤶ You can read and write arbitrary structured data using ComputeBuffers too.⤶ ⤶ ### Setting data⤶ ⤶ ```csharp⤶ var computeShader = new ComputeShader( "my_compute_shader" );⤶ ⤶ struct MyData⤶ {⤶ public float Value;⤶ }⤶ ⤶ // Allocate the GPU buffer⤶ using ( var buffer = new ComputeBuffer<MyData>( 2 ) )⤶ {⤶ // Upload data to the GPU buffer⤶ var data = new MyData[] { new MyData { Value = 1.0f }, new MyData { Value = 2.0f } };⤶ buffer.SetData( data );⤶ ⤶ // Pass the buffer to a compute shader⤶ computeShader.Attributes.Set( "myData", buffer );⤶ ⤶ // Dispatch the shader⤶ computeShader.Dispatch();⤶ }⤶ ```⤶ ⤶ ### Getting data⤶ ⤶ ```csharp⤶ var computeShader = new ComputeShader( "my_compute_shader" );⤶ ⤶ // Allocate the GPU buffer to receive data⤶ using ( var buffer = new ComputeBuffer<float>( 2 ) )⤶ {⤶ // Pass the buffer to a compute shader⤶ computeShader.Attributes.Set( "myData", buffer );⤶ ⤶ // Dispatch the shader⤶ computeShader.Dispatch();⤶ ⤶ // Get the data the compute shader has generated from the GPU⤶ var data = new float[2];⤶ buffer.GetData( data );⤶ }⤶ ```⤶ ⤶ ### Append buffers⤶ ⤶ Append buffers have a hidden counter that can be accessed with ComputeBuffer.CopyStructureCount, this means the CPU can know how many elements have been pushed to a buffer by the GPU.⤶ ⤶ ```csharp⤶ ComputeShader ??= new ComputeShader( "marchingcubes_cs" );⤶ ⤶ var countBuffer = new ComputeBuffer<int>( 1, ComputeBufferType.ByteAddress );⤶ var trianglesBuffer = new ComputeBuffer<Triangle>( 512, ComputeBufferType.Append );⤶ ⤶ ComputeShader.Attributes.Set( "Triangles", trianglesBuffer );⤶ ComputeShader.Dispatch( 8, 8, 8 );⤶ ⤶ // Copy how many triangles have been pushed to the buffer into our count buffer⤶ trianglesBuffer.CopyStructureCount( countBuffer, 0 );⤶ ⤶ // Grab the count to the CPU from the GPU buffer⤶ var count = new int[1] { 0 };⤶ countBuffer.GetData( count, 0, 1 );⤶ ⤶ // Grab that number of triangles from the append buffer⤶ var tris = new Triangle[count[0]];⤶ trianglesBuffer.GetData( tris, 0, count[0] );⤶ ⤶ ```⤶