Skip to content

Commit

Permalink
Add error handling in RdRenderer constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
pkdawson committed Oct 12, 2023
1 parent e565497 commit 67c6240
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Dear ImGui for Godot Demo.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.1.1">
<Project Sdk="Godot.NET.Sdk/4.1.2">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Dear ImGui plugin for Godot 4 (C#)

![](https://img.shields.io/static/v1?label=Godot&message=4.2&color=blue&logo=godotengine)
![](https://img.shields.io/static/v1?label=Godot&message=4.1&color=blue&logo=godotengine)
![](https://img.shields.io/static/v1?label=Godot&message=4.0&color=blue&logo=godotengine)

![](https://github.com/pkdawson/imgui-godot/actions/workflows/dotnet.yml/badge.svg)
![](https://github.com/pkdawson/imgui-godot/actions/workflows/godot.yml/badge.svg)

![screenshot](doc/screenshot.png)

Dear ImGui is a popular library for rapidly building tools for debugging and development. This plugin, with the aid of [ImGui.NET](https://github.com/mellinoe/ImGui.NET), allows you to use ImGui in Godot with C#.
[Dear ImGui](https://github.com/ocornut/imgui) is a popular library for rapidly building tools for debugging and development. This plugin, with the aid of [ImGui.NET](https://github.com/ImGuiNET/ImGui.NET), allows you to use ImGui in Godot with C#.

After installing the plugin, usage is as simple as this:
```csharp
Expand All @@ -28,9 +30,6 @@ Download

## Getting Started

### Demo

Click `Build` in the top right, then run the project.

### Your project

Expand All @@ -52,12 +51,14 @@ Click `Build` in the top right, then run the project.

In any Node's `_Process` method, use `ImGuiNET` to create your GUI. Just don't set the `ProcessPriority` in any of your Nodes to either `int.MinValue` or `int.MaxValue`.

You can also connect to the `ImGuiLayout` signal, and use ImGui in the method which handles that signal. This is strongly recommended if you're using thread groups in Godot 4.1 or later.
### Signals

You can also connect to the `ImGuiLayout` signal, and use ImGui in the method which handles that signal. This is strongly recommended if you're using process thread groups in Godot 4.1 or later.
```csharp
ImGuiLayer.Connect(OnImGuiLayout);
```

### ImGuiLayer
### Configuration

If you want to customize fonts or other settings, create an `ImGuiConfig` resource, then open the scene `res://addons/imgui-godot/ImGuiLayer.tscn` and set its `Config` property.

Expand Down Expand Up @@ -103,4 +104,4 @@ Hack font distributed under the [MIT license](https://github.com/source-foundry/

M PLUS 2 font licensed under the SIL Open Font License, Version 1.1.

This plugin's functionality relies heavily on [ImGui.NET](https://github.com/mellinoe/ImGui.NET) by Eric Mellino
This plugin's functionality relies heavily on [ImGui.NET](https://github.com/ImGuiNET/ImGui.NET) by Eric Mellino
31 changes: 25 additions & 6 deletions addons/imgui-godot/ImGuiGodot/ImGuiGD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,32 @@ public static void Init(Window mainWindow, Rid mainSubViewport, float? scale = n
// there's no way to get the actual current thread model, eg if --render-thread is used
int threadModel = (int)ProjectSettings.GetSetting("rendering/driver/threads/thread_model");

Internal.State.Instance = new(mainWindow, mainSubViewport, renderer switch
Internal.IRenderer internalRenderer;
try
{
RendererType.Dummy => new Internal.DummyRenderer(),
RendererType.Canvas => new Internal.CanvasRenderer(),
RendererType.RenderingDevice => threadModel == 2 ? new Internal.RdRendererThreadSafe() : new Internal.RdRenderer(),
_ => throw new ArgumentException("Invalid renderer", nameof(renderer))
});
internalRenderer = renderer switch
{
RendererType.Dummy => new Internal.DummyRenderer(),
RendererType.Canvas => new Internal.CanvasRenderer(),
RendererType.RenderingDevice => threadModel == 2 ? new Internal.RdRendererThreadSafe() : new Internal.RdRenderer(),
_ => throw new ArgumentException("Invalid renderer", nameof(renderer))
};
}
catch (Exception e)
{
if (renderer == RendererType.RenderingDevice)
{
GD.PushWarning($"imgui-godot: falling back to Canvas renderer ({e.Message})");
internalRenderer = new Internal.CanvasRenderer();
}
else
{
GD.PushError("imgui-godot: failed to init renderer");
internalRenderer = new Internal.DummyRenderer();
}
}

Internal.State.Instance = new(mainWindow, mainSubViewport, internalRenderer);
Internal.State.Instance.Renderer.InitViewport(mainSubViewport);
}

Expand Down
2 changes: 1 addition & 1 deletion addons/imgui-godot/ImGuiGodot/Internal/CanvasRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ private sealed class ViewportData
private readonly Dictionary<Rid, List<Rid>> _canvasItemPools = new();
private readonly Dictionary<Rid, ViewportData> _vpData = new();

public string Name => "imgui_impl_godot4_canvas";
public string Name => "godot4_net_canvas";

public void Init(ImGuiIOPtr io)
{
Expand Down
2 changes: 1 addition & 1 deletion addons/imgui-godot/ImGuiGodot/Internal/DummyRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace ImGuiGodot.Internal;

internal sealed class DummyRenderer : IRenderer
{
public string Name => "imgui_impl_godot4_dummy";
public string Name => "godot4_net_dummy";

public void Init(ImGuiIOPtr io)
{
Expand Down
22 changes: 17 additions & 5 deletions addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

namespace ImGuiGodot.Internal;

internal sealed class RdRendererException : ApplicationException
{
public RdRendererException(string message) : base(message)
{
}
}

internal class RdRenderer : IRenderer
{
protected readonly RenderingDevice RD;
Expand Down Expand Up @@ -39,21 +46,21 @@ internal class RdRenderer : IRenderer
private readonly long[] _vtxOffsets = new long[3];
private readonly Godot.Collections.Array<RDUniform> _uniformArray = new();

public string Name => "imgui_impl_godot4_rd";
public string Name => "godot4_net_rd";

public RdRenderer()
{
RD = RenderingServer.GetRenderingDevice();
if (RD is null)
{
throw new PlatformNotSupportedException("failed to get RenderingDevice");
}
throw new RdRendererException("failed to get RenderingDevice");

// set up everything to match the official Vulkan backend as closely as possible

// compiling from source takes ~400ms, so we use a SPIR-V resource
using var spirv = ResourceLoader.Load<RDShaderSpirV>("res://addons/imgui-godot/data/ImGuiShaderSPIRV.tres");
_shader = RD.ShaderCreateFromSpirV(spirv);
if (!_shader.IsValid)
throw new RdRendererException("failed to create shader");

#if IMGUI_GODOT_DEV
#pragma warning disable CA2201
Expand All @@ -62,7 +69,7 @@ public RdRenderer()
SourceFragment = _fragmentShaderSource,
SourceVertex = _vertexShaderSource,
};
using var freshSpirv = RD.ShaderCompileSpirvFromSource(src);
using var freshSpirv = RD.ShaderCompileSpirVFromSource(src);
if (!System.Linq.Enumerable.SequenceEqual(spirv.BytecodeFragment, freshSpirv.BytecodeFragment))
throw new Exception("fragment bytecode mismatch");
if (!System.Linq.Enumerable.SequenceEqual(spirv.BytecodeVertex, freshSpirv.BytecodeVertex))
Expand Down Expand Up @@ -137,6 +144,9 @@ public RdRenderer()
new RDPipelineDepthStencilState(),
blendData);

if (!_pipeline.IsValid)
throw new RdRendererException("failed to create pipeline");

// sampler used for all textures
using var samplerState = new RDSamplerState
{
Expand All @@ -148,6 +158,8 @@ public RdRenderer()
RepeatW = RenderingDevice.SamplerRepeatMode.Repeat
};
_sampler = RD.SamplerCreate(samplerState);
if (!_sampler.IsValid)
throw new RdRendererException("failed to create sampler");

_srcBuffers.Resize(3);
_uniformArray.Resize(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void Dispose()

internal sealed class RdRendererThreadSafe : RdRenderer, IRenderer
{
public new string Name => "imgui_impl_godot4_rd_mt";
public new string Name => "godot4_net_rd_mt";

private readonly object _sharedDataLock = new();
private SharedList? _dataToDraw;
Expand Down
2 changes: 1 addition & 1 deletion addons/imgui-godot/ImGuiGodot/Internal/State.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal interface IRenderer

internal sealed class State : IDisposable
{
private static readonly IntPtr _backendName = Marshal.StringToCoTaskMemAnsi("imgui_impl_godot4_net");
private static readonly IntPtr _backendName = Marshal.StringToCoTaskMemAnsi("godot4_net");
private static IntPtr _rendererName = IntPtr.Zero;
private IntPtr _iniFilenameBuffer = IntPtr.Zero;

Expand Down

0 comments on commit 67c6240

Please sign in to comment.