From d685cb49927c14052d97d86c6d3578d24184192e Mon Sep 17 00:00:00 2001 From: Patrick Dawson Date: Fri, 11 Nov 2022 21:46:32 +0100 Subject: [PATCH] clean up new renderer, prepare for beta 5 --- addons/imgui-godot/ImGuiGodot/ImGuiGD.cs | 17 ++++- addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs | 5 +- addons/imgui-godot/ImGuiGodot/Internal.cs | 26 ++++---- .../ImGuiGodot/InternalCanvasRenderer.cs | 2 + ...nalVkRenderer.cs => InternalRdRenderer.cs} | 63 +++++++++++++------ addons/imgui-godot/plugin.cfg | 2 +- 6 files changed, 79 insertions(+), 36 deletions(-) rename addons/imgui-godot/ImGuiGodot/{InternalVkRenderer.cs => InternalRdRenderer.cs} (84%) diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs index 2a65310..ff6aa2a 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs @@ -63,11 +63,11 @@ public static class ImGuiGD { } - public static void Init(float? scale = null) + public static void Init(float? scale = null, Renderer renderer = Renderer.RenderingDevice) { if (IntPtr.Size != sizeof(ulong)) { - GD.PrintErr("imgui-godot requires 64-bit pointers"); + throw new PlatformNotSupportedException("imgui-godot requires 64-bit pointers"); } if (scale != null) @@ -75,7 +75,12 @@ public static class ImGuiGD _scale = scale.Value; } - Internal.Init(); + Internal.Init(renderer switch + { + Renderer.Canvas => new InternalCanvasRenderer(), + Renderer.RenderingDevice => new InternalRdRenderer(), + _ => throw new ArgumentException("Invalid renderer", nameof(renderer)) + }); } public static void ResetFonts() @@ -179,3 +184,9 @@ public static class ImGuiGD Internal.SetIniFilename(io, fileName); } } + +public enum Renderer +{ + Canvas, + RenderingDevice +} diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs index 8ccc3d2..d265c26 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs @@ -29,6 +29,9 @@ public partial class ImGuiLayer : CanvasLayer /// [Signal] public delegate void ImGuiLayoutEventHandler(); + [Export(PropertyHint.Enum, "RenderingDevice,Canvas")] + public string Renderer = "RenderingDevice"; + private Window _window; private SubViewportContainer _subViewportContainer; private SubViewport _subViewport; @@ -56,7 +59,7 @@ public partial class ImGuiLayer : CanvasLayer VisibilityChanged += OnChangeVisibility; ImGuiGD.ScaleToDpi = ScaleToDpi; - ImGuiGD.Init(Scale); + ImGuiGD.Init(Scale, Enum.Parse(Renderer)); ImGui.GetIO().SetIniFilename(IniFilename); if (Font is not null) { diff --git a/addons/imgui-godot/ImGuiGodot/Internal.cs b/addons/imgui-godot/ImGuiGodot/Internal.cs index 248bc63..fdb293d 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal.cs @@ -11,6 +11,7 @@ namespace ImGuiGodot; internal interface IRenderer { + public string Name { get; } public void InitViewport(Viewport vp); public void CloseViewport(Viewport vp); public void RenderDrawData(Viewport vp, ImDrawDataPtr drawData); @@ -27,8 +28,9 @@ internal static class Internal private static Vector2 _mouseWheel = Vector2.Zero; private static ImGuiMouseCursor _currentCursor = ImGuiMouseCursor.None; private static readonly IntPtr _backendName = Marshal.StringToCoTaskMemAnsi("imgui_impl_godot4_net"); + private static IntPtr _rendererName = IntPtr.Zero; private static IntPtr _iniFilenameBuffer = IntPtr.Zero; - internal static IRenderer Renderer { get; } + internal static IRenderer Renderer { get; private set; } private class FontParams { @@ -46,7 +48,7 @@ internal static class Internal if (cinfo is null) { GD.PrintErr("failed to get RID constructor"); - return; + throw new PlatformNotSupportedException(); } DynamicMethod dm = new("ConstructRID", typeof(RID), new[] { typeof(ulong) }); @@ -55,17 +57,11 @@ internal static class Internal il.Emit(OpCodes.Newobj, cinfo); il.Emit(OpCodes.Ret); ConstructRID = dm.CreateDelegate>(); - -#if IMGUI_GODOT_DEV - Renderer = new InternalVkRenderer(); -#else - Renderer = new InternalCanvasRenderer(); -#endif } - public static void AddFont(FontFile fontData, float fontSize, bool merge) + public static void AddFont(FontFile fontData, int fontSize, bool merge) { - _fontConfiguration.Add(new FontParams { Font = fontData, FontSize = (int)fontSize, Merge = merge }); + _fontConfiguration.Add(new FontParams { Font = fontData, FontSize = fontSize, Merge = merge }); } private static unsafe void _AddFont(FontFile fontData, int fontSize, bool merge) @@ -196,8 +192,9 @@ internal static class Internal ImGui.GetStyle().ScaleAllSizes(scale); } - public static void Init() + public static void Init(IRenderer renderer) { + Renderer = renderer; _fontConfiguration.Clear(); if (ImGui.GetCurrentContext() != IntPtr.Zero) @@ -215,10 +212,15 @@ internal static class Internal io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors; io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset; + if (_rendererName == IntPtr.Zero) + { + _rendererName = Marshal.StringToCoTaskMemAnsi(Renderer.Name); + } + unsafe { io.NativePtr->BackendPlatformName = (byte*)_backendName; - io.NativePtr->BackendRendererName = (byte*)_backendName; + io.NativePtr->BackendRendererName = (byte*)_rendererName; } #if IMGUI_GODOT_DEV diff --git a/addons/imgui-godot/ImGuiGodot/InternalCanvasRenderer.cs b/addons/imgui-godot/ImGuiGodot/InternalCanvasRenderer.cs index 13b4c12..f45787e 100644 --- a/addons/imgui-godot/ImGuiGodot/InternalCanvasRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/InternalCanvasRenderer.cs @@ -16,6 +16,8 @@ internal class InternalCanvasRenderer : IRenderer private readonly Dictionary> _canvasItemPools = new(); private readonly Dictionary _vpData = new(); + public string Name => "imgui_impl_godot4_canvas"; + public void InitViewport(Viewport vp) { RID vprid = vp.GetViewportRid(); diff --git a/addons/imgui-godot/ImGuiGodot/InternalVkRenderer.cs b/addons/imgui-godot/ImGuiGodot/InternalRdRenderer.cs similarity index 84% rename from addons/imgui-godot/ImGuiGodot/InternalVkRenderer.cs rename to addons/imgui-godot/ImGuiGodot/InternalRdRenderer.cs index 9c9836b..76fa1cd 100644 --- a/addons/imgui-godot/ImGuiGodot/InternalVkRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/InternalRdRenderer.cs @@ -1,4 +1,3 @@ -#if IMGUI_GODOT_DEV using Godot; using ImGuiNET; using System; @@ -7,27 +6,34 @@ using System.Runtime.InteropServices; namespace ImGuiGodot; -internal class InternalVkRenderer : IRenderer +internal class InternalRdRenderer : IRenderer { private readonly RenderingDevice RD; private readonly Color[] clearColors = new[] { new Color(0f, 0f, 0f, 0f) }; - //private readonly Color[] clearColors = new[] { new Color(0.45098f, 0.54902f, 0.60f) }; private readonly RID _shader; private readonly RID _pipeline; private readonly RID _sampler; private readonly long _vtxFormat; private readonly Dictionary _framebuffers = new(); - public InternalVkRenderer() + public string Name => "imgui_impl_godot4_rd"; + + public InternalRdRenderer() { RD = RenderingServer.GetRenderingDevice(); - var src = new RDShaderSource(); - src.SourceVertex = vertexShaderSource; - src.SourceFragment = fragmentShaderSource; + // set up everything to match the official Vulkan backend as closely as possible + + // compile shader + var src = new RDShaderSource + { + SourceVertex = vertexShaderSource, + SourceFragment = fragmentShaderSource + }; var spirv = RD.ShaderCompileSpirvFromSource(src); _shader = RD.ShaderCreateFromSpirv(spirv); + // create vertex format uint vtxStride = (uint)Marshal.SizeOf(); RDVertexAttribute attrPoints = new() @@ -57,6 +63,7 @@ internal class InternalVkRenderer : IRenderer var vattrs = new Godot.Collections.Array() { attrPoints, attrUvs, attrColors }; _vtxFormat = RD.VertexFormatCreate(vattrs); + // blend state var bsa = new RDPipelineColorBlendStateAttachment { EnableBlend = true, @@ -69,15 +76,20 @@ internal class InternalVkRenderer : IRenderer DstAlphaBlendFactor = RenderingDevice.BlendFactor.OneMinusSrcAlpha, AlphaBlendOp = RenderingDevice.BlendOperation.Add, }; - var blendData = new RDPipelineColorBlendState(); - blendData.Attachments.Add(bsa); - blendData.BlendConstant = new Color(0, 0, 0, 0); + var blendData = new RDPipelineColorBlendState + { + BlendConstant = new Color(0, 0, 0, 0), + }; + blendData.Attachments.Add(bsa); + + // rasterization state var rasterizationState = new RDPipelineRasterizationState { FrontFace = RenderingDevice.PolygonFrontFace.CounterClockwise }; + // pipeline _pipeline = RD.RenderPipelineCreate( _shader, RD.ScreenGetFramebufferFormat(), @@ -88,6 +100,7 @@ internal class InternalVkRenderer : IRenderer new RDPipelineDepthStencilState(), blendData); + // sampler used for all textures var samplerState = new RDSamplerState { MinFilter = RenderingDevice.SamplerFilter.Linear, @@ -133,7 +146,7 @@ internal class InternalVkRenderer : IRenderer Buffer.BlockCopy(translate, 0, pcbuf, 8, 8); var vtxBuffers = new RID[drawData.CmdListsCount]; - var vtxArrays = new RID[drawData.CmdListsCount]; + var vtxArrays = new List>(drawData.CmdListsCount); var idxBuffers = new RID[drawData.CmdListsCount]; var idxArrays = new List(drawData.CmdListsCount); var uniformSets = new Dictionary(); @@ -151,8 +164,7 @@ internal class InternalVkRenderer : IRenderer Marshal.Copy(cmdList.IdxBuffer.Data, idxBuf, 0, idxBytes); vtxBuffers[i] = RD.VertexBufferCreate((uint)vertBuf.Length, vertBuf); - vtxArrays[i] = RD.VertexArrayCreate((uint)cmdList.VtxBuffer.Size, _vtxFormat, - new() { vtxBuffers[i], vtxBuffers[i], vtxBuffers[i] }); + vtxArrays.Add(new()); idxBuffers[i] = RD.IndexBufferCreate((uint)cmdList.IdxBuffer.Size, RenderingDevice.IndexBufferFormat.Uint16, idxBuf); @@ -161,11 +173,23 @@ internal class InternalVkRenderer : IRenderer for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; ++cmdi) { ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi]; + if (drawCmd.ElemCount == 0) + continue; + idxArrays[i][cmdi] = RD.IndexArrayCreate(idxBuffers[i], drawCmd.IdxOffset, drawCmd.ElemCount); - if (drawCmd.VtxOffset > 0) + if (!vtxArrays[i].ContainsKey(drawCmd.VtxOffset)) { - // TODO: ... + long voff = drawCmd.VtxOffset * vertSize; +#if IMGUI_GODOT_DEV + vtxArrays[i][drawCmd.VtxOffset] = RD.VertexArrayCreate((uint)cmdList.VtxBuffer.Size, _vtxFormat, + new() { vtxBuffers[i], vtxBuffers[i], vtxBuffers[i] }, + new[] { voff, voff, voff }); +#else + // TODO: offsets workaround + vtxArrays[i][drawCmd.VtxOffset] = RD.VertexArrayCreate((uint)cmdList.VtxBuffer.Size, _vtxFormat, + new() { vtxBuffers[i], vtxBuffers[i], vtxBuffers[i] }); +#endif } IntPtr texid = drawCmd.GetTexID(); @@ -195,8 +219,6 @@ internal class InternalVkRenderer : IRenderer { ImDrawListPtr cmdList = drawData.CmdListsRange[i]; - RD.DrawListBindVertexArray(dl, vtxArrays[i]); - for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; ++cmdi) { ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi]; @@ -206,6 +228,7 @@ internal class InternalVkRenderer : IRenderer RD.DrawListBindUniformSet(dl, uniformSets[drawCmd.GetTexID()], 0); RD.DrawListBindIndexArray(dl, idxArrays[i][cmdi]); + RD.DrawListBindVertexArray(dl, vtxArrays[i][drawCmd.VtxOffset]); RD.DrawListEnableScissor(dl, new Rect2( drawCmd.ClipRect.X, @@ -218,7 +241,10 @@ internal class InternalVkRenderer : IRenderer RD.FreeRid(idxArrays[i][cmdi]); } - RD.FreeRid(vtxArrays[i]); + foreach (RID rid in vtxArrays[i].Values) + { + RD.FreeRid(rid); + } RD.FreeRid(vtxBuffers[i]); RD.FreeRid(idxBuffers[i]); } @@ -277,4 +303,3 @@ void main() fColor = In.Color * texture(sTexture, In.UV.st); }"; } -#endif diff --git a/addons/imgui-godot/plugin.cfg b/addons/imgui-godot/plugin.cfg index 09233fa..b82d94a 100644 --- a/addons/imgui-godot/plugin.cfg +++ b/addons/imgui-godot/plugin.cfg @@ -3,5 +3,5 @@ name="Dear ImGui for Godot" description="Dear ImGui for Godot" author="Patrick Dawson" -version="3.2.0" +version="3.3.0" script="ImGuiPlugin.gd"