diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs
index 6056c07..08357cf 100644
--- a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs
+++ b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs
@@ -19,16 +19,14 @@ public static float JoyAxisDeadZone
}
///
- /// Setting this property will reload fonts and modify the ImGuiStyle
+ /// Setting this property will reload fonts and modify the ImGuiStyle.
+ /// Can only be set outside of a process frame (eg, use CallDeferred)
///
public static float Scale
{
get => _backend.Scale;
set
{
- //if (_inProcessFrame)
- // throw new InvalidOperationException("scale cannot be changed during process frame");
-
if (_backend.Scale != value && value >= 0.25f)
{
_backend.Scale = value;
@@ -89,9 +87,6 @@ public static void AddFontDefault()
public static void RebuildFontAtlas()
{
- //if (_inProcessFrame)
- // throw new InvalidOperationException("fonts cannot be changed during process frame");
-
_backend.RebuildFontAtlas();
}
@@ -105,6 +100,9 @@ public static void Connect(Action action)
Connect(Callable.From(action));
}
+ ///
+ /// Must call from a tool script before doing anything else
+ ///
public static bool ToolInit()
{
if (_backend is BackendNative nbe)
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs b/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs
index 2b3a52e..757e3b5 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs
@@ -168,11 +168,12 @@ private void SetupBuffers(ImDrawDataPtr drawData)
int globalIdxOffset = 0;
int globalVtxOffset = 0;
- // set up buffers
int idxBufSize = drawData.TotalIdxCount * sizeof(ushort);
byte[] idxBuf = _bufPool.Rent(idxBufSize);
+
int vertBufSize = drawData.TotalVtxCount * vertSize;
byte[] vertBuf = _bufPool.Rent(vertBufSize);
+
for (int i = 0; i < drawData.CmdLists.Size; ++i)
{
ImDrawListPtr cmdList = drawData.CmdLists[i];
diff --git a/gdext/src/RdRenderer.cpp b/gdext/src/RdRenderer.cpp
index a1c493a..ccc2df0 100644
--- a/gdext/src/RdRenderer.cpp
+++ b/gdext/src/RdRenderer.cpp
@@ -47,7 +47,6 @@ struct RdRenderer::Impl
int vtxBufferSize = 0; // size in vertices
void SetupBuffers(ImDrawData* drawData);
- void RenderOne(RID vprid, ImDrawData* drawData);
Impl()
{
@@ -84,35 +83,6 @@ void RdRenderer::Impl::SetupBuffers(ImDrawData* drawData)
{
RenderingDevice* RD = RenderingServer::get_singleton()->get_rendering_device();
- // clean out invalidated uniform sets so they can be refreshed
- for (auto it = uniformSets.begin(); it != uniformSets.end();)
- {
- if (!RD->uniform_set_is_valid(it->second))
- it = uniformSets.erase(it);
- else
- ++it;
- }
-
- // allocate merged index and vertex buffers
- if (idxBufferSize < drawData->TotalIdxCount)
- {
- if (idxBuffer.get_id() != 0)
- RD->free_rid(idxBuffer);
- idxBuffer = RD->index_buffer_create(drawData->TotalIdxCount, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16);
- idxBufferSize = drawData->TotalIdxCount;
- }
-
- if (vtxBufferSize < drawData->TotalVtxCount)
- {
- if (vtxBuffer.get_id() != 0)
- RD->free_rid(vtxBuffer);
- vtxBuffer = RD->vertex_buffer_create(drawData->TotalVtxCount * sizeof(ImDrawVert));
- vtxBufferSize = drawData->TotalVtxCount;
- }
-
- if (drawData->TotalIdxCount == 0)
- return;
-
int globalIdxOffset = 0;
int globalVtxOffset = 0;
@@ -128,27 +98,30 @@ void RdRenderer::Impl::SetupBuffers(ImDrawData* drawData)
{
ImDrawList* cmdList = drawData->CmdLists[i];
- std::copy(cmdList->IdxBuffer.begin(),
- cmdList->IdxBuffer.end(),
- reinterpret_cast(idxBuf.ptrw() + globalIdxOffset));
std::copy(cmdList->VtxBuffer.begin(),
cmdList->VtxBuffer.end(),
reinterpret_cast(vertBuf.ptrw() + globalVtxOffset));
+ globalVtxOffset += cmdList->VtxBuffer.size_in_bytes();
+ std::copy(cmdList->IdxBuffer.begin(),
+ cmdList->IdxBuffer.end(),
+ reinterpret_cast(idxBuf.ptrw() + globalIdxOffset));
globalIdxOffset += cmdList->IdxBuffer.size_in_bytes();
- globalVtxOffset += cmdList->VtxBuffer.size_in_bytes();
+ // create a uniform set for each texture
for (int cmdi = 0; cmdi < cmdList->CmdBuffer.Size; ++cmdi)
{
const ImDrawCmd& drawCmd = cmdList->CmdBuffer[cmdi];
ImTextureID texid = drawCmd.GetTexID();
if (!texid)
continue;
+ RID texrid = make_rid(texid);
+ if (!RD->texture_is_valid(texrid))
+ continue;
usedTextures.insert(texid);
if (!uniformSets.contains(texid))
{
- RID texrid = make_rid(texid);
Ref uniform;
uniform.instantiate();
uniform->set_binding(0);
@@ -157,9 +130,7 @@ void RdRenderer::Impl::SetupBuffers(ImDrawData* drawData)
uniform->add_id(texrid);
uniforms[0] = uniform;
-
- RID uniformSet = RD->uniform_set_create(uniforms, shader, 0);
- uniformSets[texid] = uniformSet;
+ uniformSets[texid] = RD->uniform_set_create(uniforms, shader, 0);
}
}
}
@@ -241,6 +212,9 @@ bool RdRenderer::Init()
{},
blend);
+ if (!impl->pipeline.is_valid())
+ return false;
+
RDSamplerState sampler_state;
sampler_state.set_min_filter(RenderingDevice::SAMPLER_FILTER_LINEAR);
sampler_state.set_mag_filter(RenderingDevice::SAMPLER_FILTER_LINEAR);
@@ -260,7 +234,8 @@ void RdRenderer::Render(RID fb, ImDrawData* drawData)
{
RenderingDevice* RD = RenderingServer::get_singleton()->get_rendering_device();
- impl->SetupBuffers(drawData);
+ if (!fb.is_valid())
+ return;
godot::PackedFloat32Array pcfloats;
pcfloats.resize(4);
@@ -270,6 +245,30 @@ void RdRenderer::Render(RID fb, ImDrawData* drawData)
pcfloats[3] = -1.0f - (drawData->DisplayPos.y * pcfloats[1]);
godot::PackedByteArray pcbuf = pcfloats.to_byte_array();
+ // allocate merged index and vertex buffers
+ if (impl->idxBufferSize < drawData->TotalIdxCount)
+ {
+ if (impl->idxBuffer.get_id() != 0)
+ RD->free_rid(impl->idxBuffer);
+ impl->idxBuffer = RD->index_buffer_create(drawData->TotalIdxCount, RenderingDevice::INDEX_BUFFER_FORMAT_UINT16);
+ impl->idxBufferSize = drawData->TotalIdxCount;
+ }
+
+ if (impl->vtxBufferSize < drawData->TotalVtxCount)
+ {
+ if (impl->vtxBuffer.get_id() != 0)
+ RD->free_rid(impl->vtxBuffer);
+ impl->vtxBuffer = RD->vertex_buffer_create(drawData->TotalVtxCount * sizeof(ImDrawVert));
+ impl->vtxBufferSize = drawData->TotalVtxCount;
+ }
+
+ // check if our font texture is still valid
+ std::erase_if(impl->uniformSets, [RD](const auto& kv) { return !RD->uniform_set_is_valid(kv.second); });
+
+ if (drawData->CmdListsCount > 0)
+ impl->SetupBuffers(drawData);
+
+ // draw
int64_t dl = RD->draw_list_begin(fb,
RenderingDevice::INITIAL_ACTION_CLEAR,
RenderingDevice::FINAL_ACTION_READ,
@@ -341,6 +340,27 @@ void RdRenderer::InitViewport(RID vprid)
RenderingServer::get_singleton()->viewport_set_clear_mode(vprid, RenderingServer::VIEWPORT_CLEAR_NEVER);
}
+void RdRenderer::FreeUnusedTextures()
+{
+ RenderingDevice* RD = RenderingServer::get_singleton()->get_rendering_device();
+
+ // clean up unused textures
+ std::vector keys;
+ keys.reserve(impl->uniformSets.size());
+ for (const auto& kv : impl->uniformSets)
+ keys.push_back(kv.first);
+
+ for (ImTextureID texid : keys)
+ {
+ if (!impl->usedTextures.contains(texid))
+ {
+ RD->free_rid(impl->uniformSets[texid]);
+ impl->uniformSets.erase(texid);
+ }
+ }
+ impl->usedTextures.clear();
+}
+
void RdRenderer::Render()
{
auto& pio = ImGui::GetPlatformIO();
@@ -353,6 +373,7 @@ void RdRenderer::Render()
Render(GetFramebuffer(vprid), vp->DrawData);
}
}
+ FreeUnusedTextures();
}
void RdRenderer::ReplaceTextureRIDs(ImDrawData* drawData)
diff --git a/gdext/src/RdRenderer.h b/gdext/src/RdRenderer.h
index 4034986..6c2c778 100644
--- a/gdext/src/RdRenderer.h
+++ b/gdext/src/RdRenderer.h
@@ -33,6 +33,7 @@ class RdRenderer : public Renderer
void Render(RID fb, ImDrawData* drawData);
static void ReplaceTextureRIDs(ImDrawData* drawData);
RID GetFramebuffer(RID vprid);
+ void FreeUnusedTextures();
private:
struct Impl;
diff --git a/gdext/src/RdRendererThreadSafe.cpp b/gdext/src/RdRendererThreadSafe.cpp
index 3f81adc..b55bbe5 100644
--- a/gdext/src/RdRendererThreadSafe.cpp
+++ b/gdext/src/RdRendererThreadSafe.cpp
@@ -1,5 +1,6 @@
#include "RdRendererThreadSafe.h"
#include "common.h"
+#include
#include
#include
@@ -51,6 +52,8 @@ struct RdRendererThreadSafe::Impl
RdRendererThreadSafe::RdRendererThreadSafe() : impl(std::make_unique())
{
+ RenderingServer* RS = RenderingServer::get_singleton();
+ RS->connect("frame_pre_draw", Callable(Engine::get_singleton()->get_singleton("ImGuiLayer"), "on_frame_pre_draw"));
}
RdRendererThreadSafe::~RdRendererThreadSafe()
@@ -64,8 +67,10 @@ void RdRendererThreadSafe::Render()
for (int i = 0; i < pio.Viewports.size(); ++i)
{
- // TODO: skip minimized windows
ImGuiViewport* vp = pio.Viewports[i];
+ if (vp->Flags & ImGuiViewportFlags_IsMinimized)
+ continue;
+
ReplaceTextureRIDs(vp->DrawData);
RID vprid = make_rid(vp->RendererUserData);
newData[i].first = GetFramebuffer(vprid);
@@ -88,15 +93,14 @@ void RdRendererThreadSafe::OnFramePreDraw()
dataArray = std::move(impl->dataToDraw);
}
- if (dataArray.size() == 0)
- return;
-
RenderingDevice* RD = RenderingServer::get_singleton()->get_rendering_device();
for (auto& kv : dataArray)
{
if (RD->framebuffer_is_valid(kv.first))
RdRenderer::Render(kv.first, kv.second->data);
}
+
+ FreeUnusedTextures();
}
} // namespace ImGui::Godot