-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using ImDrawList to render from another Thread #5776
Comments
You'll probably need to dig further and provide more details. |
What a coincidence, I just did exactly this yesterday, here's my code, it creates separated draw lists and won't be clear by the main thread so you won't have syncing/flashing issues, and it uses a simple std::mutex for locking, it's not pretty nor optimized so I don't recommend using this for performance-critical tasks class MThreadRenderer
{
private:
std::mutex m_mutex;
ImDrawData m_drawData;
std::vector<ImDrawList> m_drawLists; // the thread render to these draw lists
std::vector<ImDrawList> m_copyList; // calling EndFrame() will copy the m_drawLists to this
std::vector<ImDrawList*> m_copyPointer; // pointer to each drawlist in m_copyList, needed for m_drawData
ImGuiViewportP* m_viewport;
public:
// numDrawList = number of draw lists needed, 2 for background and foreground
MThreadRenderer(size_t numDrawList = 2, ImGuiViewport* viewport = nullptr)
{
m_viewport = static_cast<ImGuiViewportP*>(viewport ? viewport : ImGui::GetMainViewport());
m_copyList.resize(numDrawList, &GImGui->DrawListSharedData);
for (size_t i = 0; i < numDrawList; i++)
{
m_drawLists.emplace_back(&GImGui->DrawListSharedData);
m_copyPointer.emplace_back(&m_copyList[i]);
}
m_drawData.Valid = true;
m_drawData.CmdLists = m_copyPointer.data();
m_drawData.CmdListsCount = m_copyPointer.size();
}
// index=0 for the background drawlist, index=1 for the foreground, basically the z-index
inline ImDrawList& GetDrawList(size_t index = 0) noexcept
{
return m_drawLists[index];
}
inline void BeginFrame()
{
for (auto& drawList : m_drawLists)
{
drawList._ResetForNewFrame();
drawList.PushTextureID(GImGui->IO.Fonts->TexID);
drawList.PushClipRect(m_viewport->Pos, m_viewport->Pos + m_viewport->Size, false);
}
}
inline void EndFrame()
{
m_mutex.lock();
m_copyList = m_drawLists;
m_drawData.TotalVtxCount = m_drawData.TotalIdxCount = 0;
m_drawData.DisplayPos = m_viewport->Pos;
m_drawData.DisplaySize = m_viewport->Size;
m_drawData.FramebufferScale = GImGui->IO.DisplayFramebufferScale;
for (auto& drawList : m_copyList)
{
drawList._PopUnusedDrawCmd();
m_drawData.TotalVtxCount += drawList.VtxBuffer.Size;
m_drawData.TotalIdxCount += drawList.IdxBuffer.Size;
}
m_mutex.unlock();
}
inline void Render() noexcept
{
m_mutex.lock();
ImGui_ImplDX11_RenderDrawData(&m_drawData);
m_mutex.unlock();
}
}; A test thread: void threadTest(MThreadRenderer& renderer)
{
while (true)
{
renderer.BeginFrame();
ImVec2 pos = ImGui::GetMousePos();
renderer.GetDrawList(1).AddRectFilled({ 200,200 }, { 500, 500 }, 0xff0000ff);
renderer.GetDrawList(0).AddRectFilled(pos, pos + ImVec2(300, 300), 0xff00ff00);
renderer.EndFrame();
Sleep(100);
}
} You need to create an instance of MThreadRenderer renderer;
auto thread = std::thread(threadTest, std::ref(renderer));
thread.detach(); On the main thread you need to call ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
renderer.Render(); @ocornut I wonder if this code has any issues with it, I didn't look into what the It'd be nice to have a way to render an entire Begin->End window in another thread but I guess that would be so much more work to do with minor benefits |
isn't that a problem that you reset the drawlist without locking your mutex? |
@xetru No, the |
@xetru Let us know if that's solved for you. |
…DrawData itself. Faclitate user-manipulation of the array (#6406, #4879, #1878) + deep swap. (#6597, #6475, #6167, #5776, #5109, #4763, #3515, #1860) + Metrics: avoid misleadingly iterating all layers of DrawDataBuilder as everything is flattened into Layers[0] at this point. # Conflicts: # imgui.cpp # imgui_internal.h
I have posted a |
Hi,
i am trying what title says, using d3d11, but even doing it in the main imgui thread won't work for me. Creating the ImDrawList, setting _Data to ImGui::GetSharedData() and then calling _ResetForNewFrame(), after that I was expecting to be able to just draw on the list, and then replicate what ImGui::Render() does / append to draw_data, or call ImGui_ImplDX11_RenderDrawData(my_draw_data);
However, just nothing is being drawn. I couldn't find much info about this, any help appreciated.
The text was updated successfully, but these errors were encountered: