C++ GLFW&;ImGui:从主线程以外的线程创建ImGui控件

C++ GLFW&;ImGui:从主线程以外的线程创建ImGui控件,c++,multithreading,glfw,imgui,C++,Multithreading,Glfw,Imgui,我正在使用GLFW和ImGui进行一个涉及打开多个窗口的项目。到目前为止,我已经设置好了,每次必须打开一个新窗口时,我都会生成一个线程来创建自己的GLFW窗口和OpenGL上下文。thread函数的外观如下所示: window=glfwCreateWindow(640480,“你好世界”,空,空); //检查创建错误。。。 glfwMakeContextCurrent(窗口); ImGui::CreateContext(); ImGuiIO&io=ImGui::GetIO();//每个线程都应该

我正在使用GLFW和ImGui进行一个涉及打开多个窗口的项目。到目前为止,我已经设置好了,每次必须打开一个新窗口时,我都会生成一个线程来创建自己的GLFW窗口和OpenGL上下文。thread函数的外观如下所示:

window=glfwCreateWindow(640480,“你好世界”,空,空);
//检查创建错误。。。
glfwMakeContextCurrent(窗口);
ImGui::CreateContext();
ImGuiIO&io=ImGui::GetIO();//每个线程都应该这样做吗?
//正在为GLFW和OpenGL3调用特定于impl的ImGui设置方法。。。
//设置OpenGL的东西。。。
而(!glfwWindowShouldClose(窗口))
{
//这里发生了一些繁重的处理。。。
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
//ImGui代码在这里。。。
//在这里的窗口中呈现一些内容。。。
//最后呈现ImGui。。。
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(窗口);
}
//正在此处调用impl特定的ImGui关机。。。
GLFW窗口(窗口);
我知道GLFW要求您从主线程(调用
glfwInit()
的线程)轮询事件,因此我在主线程上有一个循环,可以这样做:

while(!appMustExit)
{
glfwaitevents();
}
//appMustExit是从另一个等待控制台输入的线程设置的
因此,我遇到的问题是,我的ImGui控件不响应任何类型的输入,
glfwWindowShouldClose()
如果单击关闭按钮,将永远不会返回true。似乎输入状态仅在调用
glfwPollEvents()
的线程上可用,这让我相信,在仍然使用单独的线程进行渲染时,不能将ImGui和GLFW组合在一起

我如何修复此问题以允许ImGui和这些窗口响应GLFW事件?

我以前的尝试使用单个线程来迭代每个窗口并更新/渲染它,但我希望使用线程来帮助应用程序在许多窗口打开时更好地扩展


更新:我想澄清一下,该应用程序涉及实时处理复杂的机器视觉,并且ImGui代码部分与控制和响应该机器视觉代码紧密集成。因此,我希望能够在与此处理相同的线程上调用ImGui函数,这也意味着此线程必须能够响应glfw输入。

为什么要首先创建多个线程? 您可以完美地创建多个GLFW窗口和多个亲爱的ImGui上下文,并在同一个线程中管理所有内容。从不同的线程工作只会让一切变得更难处理


在特定的亲爱的ImGui情况下,您可以使用“停靠”分支中的多视口功能,该功能本机支持在主视口之外提取任何亲爱的ImGui窗口,并为您创建/管理GLFW窗口。它全部由单个亲爱的imgui上下文处理,因此您可以从一个窗口拖放到另一个窗口。

我能够找到一种方法,通过自由使用
thead_local
说明符,将亲爱的imgui更改为(希望是)线程安全库

imconfig.h
中,我必须创建一个新的线程本地ImGuiContext指针:

struct ImGuiContext;
extern thread_local ImGuiContext* threadCTX;
#define GImGui threadCTX
imgui\u impl\u glfw.cpp
中,我必须将所有本地/静态变量更改为
thread\u local
版本:

thread_local GLFWwindow*    g_Window = NULL;    // Per-Thread Main window
thread_local GlfwClientApi  g_ClientApi = GlfwClientApi_Unknown;
thread_local double         g_Time = 0.0;
thread_local bool           g_MouseJustPressed[5] = { false, false, false, false, false };
thread_local GLFWcursor*    g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };

// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
static thread_local GLFWmousebuttonfun   g_PrevUserCallbackMousebutton = NULL;
static thread_local GLFWscrollfun        g_PrevUserCallbackScroll = NULL;
static thread_local GLFWkeyfun           g_PrevUserCallbackKey = NULL;
static thread_local GLFWcharfun          g_PrevUserCallbackChar = NULL;
同样,在
imgui\u impl\u opengl3.h
中,我对OpenGL对象句柄也做了同样的操作:

static thread_local char         g_GlslVersionString[32] = "";
static thread_local GLuint       g_FontTexture = 0;
static thread_local GLuint       g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
static thread_local int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;                                // Uniforms location
static thread_local int          g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
static thread_local unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
通过这些少量的更改,我现在能够创建一个GLFW窗口&OpenGL上下文,初始化亲爱的ImGui,并在每个线程上调用
glfwPollEvents
,而不会相互影响。实际上,创建GLFW窗口的每个线程都可以像使用“主”线程一样使用


此解决方案可能会遇到一些挫折,但在我的用例中,每个窗口都在自己的线程中运行其事件循环,有自己的OpenGL和ImGui上下文,并且这些窗口不相互交互或共享资源。

请参阅我对问题的编辑。我正在寻找一个答案,使我能够向前推进多线程,因为一个线程更新每个窗口不能与几个窗口保持快速。足够公平。但由于imgui或操作系统窗口部分不会成为您的瓶颈,因此可以从同一线程调用imgui glfw后端函数。(抱歉,在我完成之前就发送了评论!)
imgui\u impl\u glfw
正如您指出的,它不会在多线程中处理多个上下文,但为了达到这个目的,解决这个问题应该不难。至于核心imgui,您需要将GImGui定义为使用线程本地存储存储的东西,这样每个线程都可以访问和更改隐式上下文。谢谢,我在
imgui.h
中创建了一个
static thread\u local ImGuiContext*
,并且还将
imgui\u impl\u glfw.cpp
更改为只对其内部变量使用thread\u local存储。在一个窗口中,一切似乎都正常工作,不幸的是,我现在不得不等待用多个摄像头测试这一变化。。。如果它有效,我建议您使用这些更改更新您的答案,我将接受它。>在imgui.h中,我必须创建一个新的线程本地ImGuiContext指针:这可以添加到imconfig.h中,因为您不必编辑任何核心imgui文件。在中讨论了对示例后端的类似更改,请随意在那里发布,以便跟踪需求。我们可能希望重新设计所有官方后端,以使该用例更容易。