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] );⤶
⤶
```⤶