Revision Difference
Compute_Shaders#551338
<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 );⤶
⤶
// This sets the initial UAV counter for an AppendStructuredBuffer⤶
ComputeShader.Attributes.Set( "Triangles", 0 );⤶
⤶
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] );
```