Last active
December 11, 2025 16:03
-
-
Save w0wca7a/98ed3de59218545b77c2a2020599b817 to your computer and use it in GitHub Desktop.
Getting data from the SDSL Compute Shader in the Stride game engine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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