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.
var computeShader = new ComputeShader( "my_compute_shader" );
var texture = Texture.Create( 512, 512 )
.WithUAVBinding()
.WithFormat( ImageFormat.RGBA16161616F )
.Finish();
computeShader.Attributes.Set( "OutputTexture", texture );
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
{
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
var computeShader = new ComputeShader( "my_compute_shader" );
struct MyData
{
public float Value;
}
using ( var buffer = new ComputeBuffer<MyData>( 2 ) )
{
var data = new MyData[] { new MyData { Value = 1.0f }, new MyData { Value = 2.0f } };
buffer.SetData( data );
computeShader.Attributes.Set( "myData", buffer );
computeShader.Dispatch();
}
Getting data
var computeShader = new ComputeShader( "my_compute_shader" );
using ( var buffer = new ComputeBuffer<float>( 2 ) )
{
computeShader.Attributes.Set( "myData", buffer );
computeShader.Dispatch();
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.
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.Attributes.Set( "Triangles", 0 );
ComputeShader.Dispatch( 8, 8, 8 );
trianglesBuffer.CopyStructureCount( countBuffer, 0 );
var count = new int[1] { 0 };
countBuffer.GetData( count, 0, 1 );
var tris = new Triangle[count[0]];
trianglesBuffer.GetData( tris, 0, count[0] );