我正在使用GLFW和ImGui进行一个涉及打开多个窗口的项目。到目前为止,我已经设置了这个,以便每次必须打开一个新窗口时,我都会生成一个线程,该线程创建自己的GLFW窗口和OpenGL上下文。线程函数看起来像这样:
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
// Check for creation error...
glfwMakeContextCurrent(window);
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); // Is this supposed to be done per-thread?
// Calling specific impl-specific ImGui setup methods for GLFW & OpenGL3...
// Set up OpenGL stuff ...
while (!glfwWindowShouldClose(window))
{
// Some heavy-duty processing happens here...
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// ImGui code is here...
// Rendering some stuff in the window here...
// Render ImGui last...
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
// Calling impl-specific ImGui shutdown here...
glfwDestroyWindow(window);
我知道GLFW要求你从主线程(调用glfwInit()
的那个线程)轮询事件,所以我在主线程上有一个循环来做这件事:
while (!appMustExit)
{
glfwWaitEvents();
}
// appMustExit is set from another thread that waits for console input
所以我遇到的问题是,我的ImGui控件不响应任何类型的输入,如果我点击关闭按钮,glfwWindowShouldClose()
永远不会返回true。似乎输入状态只在调用glfwPollEvents()
的线程上可用,这让我相信你不能在使用单独的线程进行渲染的同时将ImGui和GLFW结合起来!
如何修复此问题以允许ImGui和这些窗口响应GLFW事件?
我以前尝试使用单个线程来迭代每个窗口并更新/呈现它,但我希望使用线程来帮助应用程序在打开许多窗口时更好地扩展。
**更新:**我想澄清一下,这个应用程序涉及到实时处理复杂的机器视觉,而ImGui代码部分与控制和响应这个机器视觉代码高度集成,因此我希望能够在处理这个过程的同一个线程上调用ImGui函数,这也意味着这个线程必须能够响应glfw输入。
3条答案
按热度按时间bqujaahr1#
我能够找到一种方法,将Dear ImGui更改为(希望如此)线程安全库,并自由使用
thead_local
说明符。在
imconfig.h
中,我必须创建一个新的线程本地ImGuiContext指针:在
imgui_impl_glfw.cpp
中,我必须将所有的局部/静态变量都更改为thread_local
版本:同样,在
imgui_impl_opengl3.h
中,我对OpenGL对象句柄做了同样的操作:有了这几个变化,我现在可以创建一个GLFW窗口和OpenGL上下文,初始化Dear ImGui,并在每个线程上调用
glfwPollEvents
,而不会相互影响。本质上,每个创建GLFW窗口的线程都可以像“主”线程一样使用。这个解决方案可能有一些挫折,但它似乎对我的用例工作得很好,其中每个窗口在自己的线程中运行其事件循环,有自己的OpenGL和ImGui上下文,并且窗口不相互交互或共享资源。
ylamdve62#
为什么你首先要创建多个线程?你可以完美地创建多个GLFW窗口和多个Dear ImGui上下文,并在同一个线程中管理所有内容。从不同的线程工作只会使一切更加难以处理。
在Dear ImGui的特定情况下,您可以使用'对接'分支中的多视口功能,该功能原生地支持提取主视口之外的任何dear imgui窗口,并为您创建/管理GLFW窗口。所有这些都由单个dear imgui上下文处理,因此您可以从一个窗口拖放到另一个窗口。
13z8s7eq3#
正如你所发现的,
thread_local
使事情变得更快。它通过创建ImGuiContext* threadCTX
的单独示例并将它们传递给执行多线程的各个线程来实现这一魔力。因此每个核心不必竞争访问公共资源否则将是单个ImGuiContext* threadCTX
。线程争用共享资源会影响性能
ImGui代码部分与控制和响应此机器视觉代码高度集成。
正如你所提到的,ImGui试图多次跨多个线程访问单个资源;那么每个核心都会竞争(最新/正确)状态,因为它现在是共享资源。由于这是共享的,它可能不会被加载该高速缓存中,并且每次线程试图访问该示例时,它都会使缓存内存无效。(快速内存)可能是瓶颈。CPU正在浪费时间获取共享资源。
最好不要将你的代码与ImGui或任何其他共享示例集成在一起。话虽如此,我有一些建议......以下是一些你可以做的建议,但没有实现/测试。
建议?
这取决于您的实现。
1.如果可以使用
atomics
将线程用作标志来同步线程,则可以提高性能。例如,仅在epoch或完整训练循环完成后调用每个线程中的clear/read/write,同时保持特定状态。但是,您希望在线程之间共享的内容应该非常具体。不要在每个线程之间共享示例,也不要在每个线程的每次传递时调用它们。并且窗口不相互交互或共享资源。
1.在主线程中创建一个 Package 器函数,该函数选择一个渲染上下文,该渲染上下文打开调用共享示例的ImGui循环,临时将glfw回调绑定到特定的渲染上下文。
当处理边缘情况时,这两个都是一个麻烦的IMHO。如果有人有更好的想法,我想他们的建议。
ML特定建议:
1.为了共享ML资源,明确哪些资源需要共享。在一个时期完成时,从每个线程进行写入文件并关闭文件,然后向每个线程分派第n个线程已经完成任务,或者让每个线程决定何时检查主线程上的共享/存储/静态状态(也许在这里实现互斥锁是个好主意)。这个调用无论如何都需要该高速缓存无效,因为它需要将新数据加载到检查点文件或从检查点文件加载新数据。