在两个线程中使用两个 OpenGL 上下文的问题(每个线程一个)

问题描述 投票:0回答:1

我一直在一个线程中使用一个 OpenGL 上下文(非常简单),如下所示:

int main
{
    // Initialize OpenGL (GLFW / GLEW)
    Compile_Shaders();
    while (glfwWindowShouldClose(WindowHandle) == 0)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glfwPollEvents();
        
        Calculate_Something(); // Compute Shader
        glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
        GLfloat* mapped = (GLfloat*)(glMapNamedBuffer(bufferResult, GL_READ_ONLY));
        memcpy(Result, mapped, sizeof(GLfloat) * ResX * ResY);
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);

        Render(Result);
        ImGui_Stuff();

        glfwSwapBuffers(WindowHandle);
    }
}

在计算着色器的计算花费更长的时间之前,这会很好地工作。然后它停止主循环。我一直在尝试使用

glFenceSync
但是
glfwSwapBuffers
总是要等到计算着色器完成。

现在我尝试了另一种方法:在另一个线程中为计算着色器生成一个单独的 OpenGL 上下文,如下所示:

void ComputeThreadFunc()
{
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* WindowHandleCompute = glfwCreateWindow(50, 5, "Something", NULL, NULL);
    if (WindowHandle == NULL)
    {
        std::cout << "Failed to open GLFW window." << std::endl;
        return;
    }

    GLuint Framebuffer;
    glfwMakeContextCurrent(WindowHandle);
    glGenFramebuffers(1, &Framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer);

    // Compile compute shader

    while (true)
    {
        Calculate_Something();
        glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
        GLfloat* mapped = (GLfloat*)(glMapNamedBuffer(bufferResult, GL_READ_ONLY));
        memcpy(Result, mapped, sizeof(GLfloat) * ResX * ResY);
        glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
        
        Sleep(100); // Tried different values here to make sure the GPU isn't too saturated
    }
}

我将主要功能更改为:

int main
{
    // Initialize OpenGL (GLFW / GLEW)
    std::thread ComputeThread = std::thread(&ComputeThreadFunc);
    while (glfwWindowShouldClose(WindowHandle) == 0)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glfwPollEvents();

        Render(Result);
        ImGui_Stuff();

        glfwSwapBuffers(WindowHandle);
    }
}

现在我看到的似乎总是在两张图片之间切换(可能是启动后的前两张)。我认为计算着色器/线程给出了正确的结果(无法真正检查,因为主循环不显示它)。

我在这里错过了什么?这两个线程不使用共享资源/缓冲区(据我所知)。我为计算线程生成了一个单独的帧缓冲区。我是否必须生成额外的缓冲区(当然会生成计算着色器所需的所有缓冲区)或以某种方式同步(结果存储在 C++ 数组中,因此 OpenGL 缓冲区可以完全独立)?

这种方法应该普遍有效吗?如果是这样,是否有我没有考虑到的一般考虑因素?如果需要其他代码,请告诉我。

编辑:

所以,我只是玩弄

Sleep(5000)
,看看什么时候会发生上述错误。当我在
glMapNamedBuffer
之前拨打此电话时,主窗口似乎工作了 5 秒钟。放置在这个调用之后它会立即中断。对于多个 OpenGL 上下文,我必须考虑这个调用有什么特别之处吗?

c++ opengl glfw openglcontext
1个回答
0
投票

使用 GLFW 创建窗口只能在主线程中进行,如 GLFW 文档的“线程安全”部分所述

其他一些方法如

glfwMakeContextCurrent
也可能从辅助线程调用,所以你要做的是从主线程创建所有窗口,然后在计算线程中使用其中一个窗口。

基本结构:

int main()
{
  //Create Window 1
  auto window1 = ...  

  //Create Window 2
  auto window2 = ...

  //Start thread
  std::thread ComputeThread = std::thread(&ComputeThreadFunc, window2);

  //Render onto window1
  glfwMakeContextCurrent(window1);

  while (glfwWindowShouldClose(window1) == 0)
  {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glfwPollEvents();

      Render(Result);
      ImGui_Stuff();

      glfwSwapBuffers(window1);
  }
}
void ComputeThreadFunc(GLFWWindow* window2)
{
    GLuint Framebuffer;
    glfwMakeContextCurrent(window2);
    glGenFramebuffers(1, &Framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer);

    // Compile compute shader

    while (true)
    {
        Calculate_Something();
        glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
        GLfloat* mapped = (GLfloat*)(glMapNamedBuffer(bufferResult, GL_READ_ONLY));
        memcpy(Result, mapped, sizeof(GLfloat) * ResX * ResY);
        Sleep(100); // Tried different values here to make sure the GPU isn't too saturated
    }
}

另请注意,当前缓冲区映射永远不会取消映射,因此您可能应该在

glUnmapNamedBuffer
行之后调用
memcpy
。或者您可以使用持久映射缓冲区。

© www.soinside.com 2019 - 2024. All rights reserved.