Skip to content

Instantly share code, notes, and snippets.

@w0wca7a
Last active December 11, 2025 16:03
Show Gist options
  • Select an option

  • Save w0wca7a/98ed3de59218545b77c2a2020599b817 to your computer and use it in GitHub Desktop.

Select an option

Save w0wca7a/98ed3de59218545b77c2a2020599b817 to your computer and use it in GitHub Desktop.
Getting data from the SDSL Compute Shader in the Stride game engine
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Graphics;
using Stride.Rendering;
using Stride.Rendering.ComputeEffect;
public class GPUBuffer : SyncScript
{
private ComputeEffectShader computeEffectShader;
private const int DataCount = 4096;
private RenderDrawContext renderDrawContext;
private CommandList commandList;
private Buffer<Vector3> _inputBufferA_GPU;
private Buffer<Vector3> _inputBufferB_GPU;
private Buffer<Vector3> _outputBuffer_GPU;
private float t;
//CPU Arrays(RAM)
private Vector3[] _inputArrayA_CPU;
private Vector3[] _inputArrayB_CPU;
public override void Start()
{
base.Start();
_inputArrayA_CPU = new Vector3[DataCount];
_inputArrayB_CPU = new Vector3[DataCount];
for (int i = 0; i < DataCount; i++)
{
_inputArrayA_CPU[i] = new Vector3(i, i % 5, i*i);
_inputArrayB_CPU[i] = new Vector3(i % 5, i, 0);
}
commandList = Services.GetService<GraphicsContext>().CommandList;
RenderContext renderContext = RenderContext.GetShared(Services);
renderDrawContext = new RenderDrawContext(Services, renderContext, Game.GraphicsContext);
_inputBufferA_GPU = Buffer.New(GraphicsDevice, _inputArrayA_CPU, BufferFlags.StructuredBuffer | BufferFlags.ShaderResource);
_inputBufferB_GPU = Buffer.New(GraphicsDevice, _inputArrayB_CPU, BufferFlags.StructuredBuffer | BufferFlags.ShaderResource);
_outputBuffer_GPU = Buffer.New<Vector3>(GraphicsDevice, DataCount, BufferFlags.RawBuffer | BufferFlags.UnorderedAccess);
computeEffectShader = new(renderContext);
computeEffectShader.ShaderSourceName = "GPUBufferShader";
//binding to shader keys
computeEffectShader.Parameters.Set(GPUBufferShaderKeys.GPUBufferA, _inputBufferA_GPU);
computeEffectShader.Parameters.Set(GPUBufferShaderKeys.GPUBufferB, _inputBufferB_GPU);
computeEffectShader.Parameters.Set(GPUBufferShaderKeys.OutputBuffer, _outputBuffer_GPU);
}
public override void Update()
{
t += 0.01f;
if (t >= 1) t = 0;
DebugText.Print(t.ToString(), new Int2(640, 20));
computeEffectShader.Parameters.Set(GPUBufferShaderKeys.LerpValue, t);
computeEffectShader.Draw(renderDrawContext);
commandList.Dispatch(64, 1, 1); // for threads mode in shader
// Note: the copy operation from GPU to CPU can be slow with big data sets
var buffer = computeEffectShader.Parameters.Get(GPUBufferShaderKeys.OutputBuffer);
var data = buffer.GetData<Vector3>(commandList);
for (int i = 1; i < DataCount/64; i++)
{
DebugText.Print($"X {data[i].X:F2}", new Int2(40, 12 *i));
DebugText.Print($"Y {data[i].Y:F2}", new Int2(120, 12*i));
DebugText.Print($"Z {data[i].Z:F2}", new Int2(200, 12*i));
}
}
}
shader GPUBufferShader : ComputeShaderBase
{
stage float LerpValue;
struct VertexInput
{
float3 Position;
};
struct VertexOutput
{
stage float3 Position : POSITION;
};
StructuredBuffer<VertexInput> GPUBufferA;
StructuredBuffer<VertexInput> GPUBufferB;
stage RWStructuredBuffer<VertexOutput> OutputBuffer;
override void Compute()
{
// run with threads (more efficient)
uint trx = streams.DispatchThreadId.x;
if(trx >= 4096) return; // operations count can be out from range, so we must break operation
VertexInput inputA = GPUBufferA[trx];
VertexInput inputB = GPUBufferB[trx];
VertexOutput output;
output.Position = lerp(inputA.Position, inputB.Position, LerpValue);
OutputBuffer[trx] = output;
// repeat code with 'for'
//for (uint i = 0; i<4096;i++)
//{
// VertexInput inputA = GPUBufferA[i];
// VertexInput inputB = GPUBufferB[i];
// VertexOutput output;
// output.Position = lerp(inputA.Position, inputB.Position, LerpValue);
// OutputBuffer[i] = output;
//}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment