Skip to content

Commit

Permalink
C++ renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
pkdawson committed Apr 28, 2024
1 parent 172989e commit b6c5db1
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 51 deletions.
12 changes: 5 additions & 7 deletions addons/imgui-godot/ImGuiGodot/ImGuiGD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ public static float JoyAxisDeadZone
}

/// <summary>
/// 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)
/// </summary>
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;
Expand Down Expand Up @@ -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();
}

Expand All @@ -105,6 +100,9 @@ public static void Connect(Action action)
Connect(Callable.From(action));
}

/// <summary>
/// Must call from a tool script before doing anything else
/// </summary>
public static bool ToolInit()
{
if (_backend is BackendNative nbe)
Expand Down
3 changes: 2 additions & 1 deletion addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
99 changes: 60 additions & 39 deletions gdext/src/RdRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ struct RdRenderer::Impl
int vtxBufferSize = 0; // size in vertices

void SetupBuffers(ImDrawData* drawData);
void RenderOne(RID vprid, ImDrawData* drawData);

Impl()
{
Expand Down Expand Up @@ -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;

Expand All @@ -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<ImDrawIdx*>(idxBuf.ptrw() + globalIdxOffset));
std::copy(cmdList->VtxBuffer.begin(),
cmdList->VtxBuffer.end(),
reinterpret_cast<ImDrawVert*>(vertBuf.ptrw() + globalVtxOffset));
globalVtxOffset += cmdList->VtxBuffer.size_in_bytes();

std::copy(cmdList->IdxBuffer.begin(),
cmdList->IdxBuffer.end(),
reinterpret_cast<ImDrawIdx*>(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<RDUniform> uniform;
uniform.instantiate();
uniform->set_binding(0);
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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<ImTextureID> 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();
Expand All @@ -353,6 +373,7 @@ void RdRenderer::Render()
Render(GetFramebuffer(vprid), vp->DrawData);
}
}
FreeUnusedTextures();
}

void RdRenderer::ReplaceTextureRIDs(ImDrawData* drawData)
Expand Down
1 change: 1 addition & 0 deletions gdext/src/RdRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 8 additions & 4 deletions gdext/src/RdRendererThreadSafe.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "RdRendererThreadSafe.h"
#include "common.h"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/rendering_server.hpp>
#include <mutex>

Expand Down Expand Up @@ -51,6 +52,8 @@ struct RdRendererThreadSafe::Impl

RdRendererThreadSafe::RdRendererThreadSafe() : impl(std::make_unique<Impl>())
{
RenderingServer* RS = RenderingServer::get_singleton();
RS->connect("frame_pre_draw", Callable(Engine::get_singleton()->get_singleton("ImGuiLayer"), "on_frame_pre_draw"));
}

RdRendererThreadSafe::~RdRendererThreadSafe()
Expand All @@ -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);
Expand All @@ -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

0 comments on commit b6c5db1

Please sign in to comment.