No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ComputeRendererFeature.cs 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Rendering.RenderGraphModule;
  4. using UnityEngine.Rendering;
  5. using UnityEngine.Rendering.Universal;
  6. // This RendererFeature shows how a compute shader can be used together with RenderGraph.
  7. // What this example doesn't show is that it can run together with render passes. If the
  8. // compute shader is using resources which are also used by render passes then a dependency
  9. // between the passes are created as they would have done for two render passes.
  10. public class ComputeRendererFeature : ScriptableRendererFeature
  11. {
  12. // We will treat the compute pass as a normal Scriptable Render Pass.
  13. class ComputePass : ScriptableRenderPass
  14. {
  15. // Compute shader.
  16. ComputeShader cs;
  17. // Compute buffers:
  18. GraphicsBuffer inputBuffer;
  19. GraphicsBuffer outputBuffer;
  20. // Reflection of the data output. I use a preallocated list to avoid memory
  21. // allocations each frame.
  22. int[] outputData = new int[20];
  23. // Constructor is used to initialize the compute buffers.
  24. public ComputePass()
  25. {
  26. BufferDesc desc = new BufferDesc(20, sizeof(int));
  27. inputBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 20, sizeof(int));
  28. var list = new List<int>();
  29. for (int i = 0; i < 20; i++)
  30. {
  31. list.Add(i);
  32. }
  33. inputBuffer.SetData(list);
  34. outputBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 20, sizeof(int));
  35. // We don't need to initialize the output normaly with data but I read the
  36. // buffer from the start when each frame is starting to look at last frames result.
  37. outputBuffer.SetData(list);
  38. }
  39. // Setup function to transfer the compute shader from the renderer feature to
  40. // the render pass.
  41. public void Setup(ComputeShader cs)
  42. {
  43. this.cs = cs;
  44. }
  45. // PassData is used to pass data when recording to the execution of the pass.
  46. class PassData
  47. {
  48. // Compute shader.
  49. public ComputeShader cs;
  50. // Buffer handles for the compute buffers.
  51. public BufferHandle input;
  52. public BufferHandle output;
  53. }
  54. // Records a render graph render pass which blits the BlitData's active texture back to the camera's color attachment.
  55. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  56. {
  57. // Last frame data should be done. Retrive the data if valid.
  58. outputBuffer.GetData(outputData);
  59. Debug.Log($"Output from compute shader: {string.Join(", ", outputData)}");
  60. // We need to import buffers when they are created outside of the render graph.
  61. BufferHandle inputHandle = renderGraph.ImportBuffer(inputBuffer);
  62. BufferHandle outputHandle = renderGraph.ImportBuffer(outputBuffer);
  63. // Starts the recording of the render graph pass given the name of the pass
  64. // and outputting the data used to pass data to the execution of the render function.
  65. // Notice that we use "AddComputePass" when we are working with compute.
  66. using (var builder = renderGraph.AddComputePass("ComputePass", out PassData passData))
  67. {
  68. // Set the pass data so the data can be transfered from the recording to the execution.
  69. passData.cs = cs;
  70. passData.input = inputHandle;
  71. passData.output = outputHandle;
  72. // UseBuffer is used to setup render graph dependencies together with read and write flags.
  73. builder.UseBuffer(passData.input);
  74. builder.UseBuffer(passData.output, AccessFlags.Write);
  75. // The execution function is also call SetRenderfunc for compute passes.
  76. builder.SetRenderFunc((PassData data, ComputeGraphContext cgContext) => ExecutePass(data, cgContext));
  77. }
  78. }
  79. // ExecutePass is the render function set in the render graph recordings.
  80. // This is good practice to avoid using variables outside of the lambda it is called from.
  81. // It is static to avoid using member variables which could cause unintended behaviour.
  82. static void ExecutePass(PassData data, ComputeGraphContext cgContext)
  83. {
  84. // Attaches the compute buffers.
  85. cgContext.cmd.SetComputeBufferParam(data.cs, data.cs.FindKernel("CSMain"), "inputData", data.input);
  86. cgContext.cmd.SetComputeBufferParam(data.cs, data.cs.FindKernel("CSMain"), "outputData", data.output);
  87. // Dispaches the compute shader with a given kernel as entrypoint.
  88. // The amount of thread groups determine how many groups to execute of the kernel.
  89. cgContext.cmd.DispatchCompute(data.cs, data.cs.FindKernel("CSMain"), 1, 1, 1);
  90. }
  91. }
  92. [SerializeField]
  93. ComputeShader computeShader;
  94. ComputePass m_ComputePass;
  95. /// <inheritdoc/>
  96. public override void Create()
  97. {
  98. // Initialize the compute pass.
  99. m_ComputePass = new ComputePass();
  100. // Sets the renderer feature to execute before rendering.
  101. m_ComputePass.renderPassEvent = RenderPassEvent.BeforeRendering;
  102. }
  103. // Here you can inject one or multiple render passes in the renderer.
  104. // This method is called when setting up the renderer once per-camera.
  105. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  106. {
  107. // Check if the system support compute shaders, if not make an early exit.
  108. if (!SystemInfo.supportsComputeShaders)
  109. {
  110. Debug.LogWarning("Device does not support compute shaders. The pass will be skipped.");
  111. return;
  112. }
  113. // Skip the render pass if the compute shader is null.
  114. if (computeShader == null)
  115. {
  116. Debug.LogWarning("The compute shader is null. The pass will be skipped.");
  117. return;
  118. }
  119. // Call Setup on the render pass and transfer the compute shader.
  120. m_ComputePass.Setup(computeShader);
  121. // Enqueue the compute pass.
  122. renderer.EnqueuePass(m_ComputePass);
  123. }
  124. }