Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions AComputeC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System.Diagnostics;
using Godot;

public partial class AComputeC
{
private readonly GodotObject m_AComputeShader;

/// <summary>
/// Create an ACompute shader wrapper for use within C# scripts.
/// </summary>
/// <param name="shaderName"></param>
/// <param name="aComputePath"></param>
public AComputeC(string shaderName, string aComputePath = "res://acompute.gd")
{
GDScript shaderResource = GD.Load<GDScript>(aComputePath);
Debug.Assert(shaderResource != null, "Make sure the aComputePath points to the location of the acompute.gd script.");

// Create the acompute.gd node
this.m_AComputeShader = (GodotObject)shaderResource.New(shaderName);
}

/// <summary>
/// Gets the Rid for the kernel at the specified index.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public Rid GetKernel(int index)
{
return (Rid)m_AComputeShader.Call("get_kernel", index);
}

/// <summary>
/// Set the shader push constant byte array.
/// </summary>
/// <param name="pushConstants"></param>
public void SetPushConstant(ref byte[] pushConstants)
{
m_AComputeShader.Call("set_push_constant", pushConstants);
}

/// <summary>
/// Set a texture resource bound to the binding. The binding value must match the value in the shader file.
/// </summary>
/// <param name="binding"></param>
/// <param name="texture"></param>
public void SetTexture(int binding, Rid texture)
{
m_AComputeShader.Call("set_texture", binding, texture);
}

/// <summary>
/// Set a uniform buffer resource bound to the binding. The binding value must match the value in the shader file.
/// </summary>
/// <param name="binding"></param>
/// <param name="uniformArray"></param>
public void SetUniformBuffer(int binding, ref byte[] uniformArray)
{
m_AComputeShader.Call("set_uniform_buffer", binding, uniformArray);
}

/// <summary>
/// Set the compute shader to run.
/// </summary>
/// <param name="xGroups"></param>
/// <param name="yGroups"></param>
/// <param name="zGroups"></param>
/// <param name="kernelIndex"></param>
public void Dispatch(int kernelIndex, int xGroups, int yGroups, int zGroups)
{
m_AComputeShader.Call("dispatch", kernelIndex, xGroups, yGroups, zGroups);
}

/// <summary>
/// Free the shader resources.
/// </summary>
public void Free()
{
m_AComputeShader.Call("free");
}
}
63 changes: 63 additions & 0 deletions Examples/ExposureCompositorEffectC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Godot;
using System.Runtime.InteropServices;

[GlobalClass]
[Tool]
public partial class ExposureCompositorEffectC : CompositorEffect
{

[ExportGroup("Shader Settings")]
[Export]
private Vector4 m_exposure = new(2, 1, 1, 1);

private AComputeC m_newShader;

/// <summary>
/// Example compositor effect using the C# shader wrapper.
/// </summary>
public ExposureCompositorEffectC() : base()
{
RenderingServer.CallOnRenderThread(Callable.From(() =>
{
this.m_newShader = new AComputeC("exposure_example");
}));
}

public override void _RenderCallback(int effectCallbackType, RenderData renderData)
{
if (!this.Enabled) return;
if (effectCallbackType != (int)EffectCallbackTypeEnum.PostTransparent) return;

RenderSceneBuffersRD renderSceneBuffers = (RenderSceneBuffersRD)renderData.GetRenderSceneBuffers();

Vector2I size = renderSceneBuffers.GetInternalSize();
if (size.X == 0 && size.Y == 0)
{
GD.PushError("Rendering to 0x0 buffer");
return;
}

int xGroups = (size.X - 1) / 8 + 1;
int yGroups = (size.Y - 1) / 8 + 1;
int zGroups = 1;

byte[] pushConstant = MemoryMarshal.AsBytes([size.X, size.Y, 0.0f, 0.0f]).ToArray();
byte[] uniformArray = MemoryMarshal.AsBytes([this.m_exposure.X, this.m_exposure.Y, this.m_exposure.Z, this.m_exposure.W]).ToArray();

Rid inputImage = renderSceneBuffers.GetColorLayer(0);

this.m_newShader.SetPushConstant(ref pushConstant);
this.m_newShader.SetTexture(0, inputImage);
this.m_newShader.SetUniformBuffer(1, ref uniformArray);
this.m_newShader.Dispatch(0, xGroups, yGroups, zGroups);
}

public override void _Notification(int what)
{
if (what == NotificationPredelete)
{
this.m_newShader.Free();
}
}

}