To create a render pass that writes to and reads output data from a compute shaderA program that runs on the GPU. More info
See in Glossary, do the following:
To check if a platform supports compute shaders, use the SystemInfo.supportsComputeShaders API
When you create a ScriptableRenderPass, do the following:
AddComputePass instead of AddRasterRenderPass.ComputeGraphContext instead of RasterGraphContext.For example:
class ComputePass : ScriptableRenderPass
{
...
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer contextData)
{
...
// Use AddComputePass instead of AddRasterRenderPass.
using (var builder = renderGraph.AddComputePass("MyComputePass", out PassData data))
{
...
// Use ComputeGraphContext instead of RasterGraphContext.
builder.SetRenderFunc(static (PassData data, ComputeGraphContext context) => ExecutePass(data, context));
...
}
}
}
To create a buffer the compute shader outputs to, follow these steps:
Inside RecordRenderGraph, create a graphics buffer using CreateBuffer and keep the handle. For example:
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
// Create the output buffer as a structured buffer of 20 ints
BufferDesc desc = new BufferDesc
{
name = "OutputBuffer",
count = 20,
stride = sizeof(int),
target = GraphicsBuffer.Target.Structured
};
m_OutputBufferHandle = renderGraph.CreateBuffer(desc);
// Add the compute pass
using (var builder = renderGraph.AddComputePass("ComputePass", out PassData passData))
{
// Set the pass data
passData.output = m_OutputBufferHandle;
}
}
Use the UseBuffer method to declare the buffer as an output of this pass in the render graph system. For example:
builder.UseBuffer(passData.output, AccessFlags.Write);
Follow these steps:
Pass the compute shader to the render pass. For example, in a ScriptableRendererFeature class, expose a ComputeShader property, then pass the compute shader into the render pass class.
Add a ComputeShader field to your pass data, and set it to the compute shader. For example:
// Add a `ComputeShader` field to your pass data
class PassData
{
...
public ComputeShader computeShader;
}
// Set the `ComputeShader` field to the compute shader
passData.computeShader = yourComputeShader;
In your SetRenderFunc method, use the SetComputeBufferParam API to attach the buffer to the compute shader. For example:
// The first parameter is the compute shader
// The second parameter is the function that uses the buffer
// The third parameter is the StructuredBuffer output variable to attach the buffer to
// The fourth parameter is the handle to the output buffer
context.commandBuffer.SetComputeBufferParam(passData.computeShader, passData.computeShader.FindKernel("Main"), "outputData", passData.output);
Use the DispatchCompute API to execute the compute shader.
context.commandBuffer.DispatchCompute(passData.computeShader, passData.computeShader.FindKernel("Main"), 1, 1, 1);
To fetch the data from the output buffer, add a pass to read the data back from the GPU to the CPU using the RequestAsyncReadback API.
You can only fetch the data after the render pass executes and the compute shader finishes running.
For example:
Create data for the pass that will read the buffer back.
// Data container for the pass that reads back from the GPU
class ReadbackPassData
{
// The buffer to read back from
public BufferHandle processedDataBuffer;
}
Provide the output buffer handle to the pass.
passData.processedDataBuffer = m_OutputBufferHandle;
Give the pass read access to the buffer.
// Declare read access to the buffer
builder.UseBuffer(passData.processedDataBuffer, AccessFlags.Read);
Request asynchronous readback with the RequestAsyncReadback API.
context.commandBuffer.RequestAsyncReadback(passData.processedDataBuffer, (AsyncGPUReadbackRequest request) =>
{
// Get the data
int result = request.GetData<int>();
})
For a full example, refer to the example called Compute in the render graph system URP package samples.