I have been using one OpenGL-context in one thread (very simplyfied) like this:
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);
}
}
This works well until the calculations of the compute shader take longer. Then it stalls the main-loop. I have been trying to use glFenceSync
but glfwSwapBuffers
always has to wait until the compute shader is done.
Now I tried another approach: Generating a seperate OpenGL-context in another thread for the compute shader like this:
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
}
}
I changed the main-function to:
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);
}
}
Now what I see always seems to switch between two images (maybe the first two after startup). I think the compute-shader/-thread gives correct results (can't really check, because the main-loop doesn't display it).
What am I missing here? The two threads don't use shared ressources/buffers (that I know of). I generated a seperate framebuffer for the compute-thread. Do I have to generate additional buffers (all the buffers the compute-shader needs are of course generated) or synchronize somehow (the result is stored in a C++-array, so the OpenGL-buffers can be completely seperate)?
Should this approach work in general? And if so, are there general considerations that I did not take into account? If additional code is needed, please let me know.
Edit:
So, I just played around with Sleep(5000)
to see when exactly the above error occurs. When I place this call before glMapNamedBuffer
the main window seems to work for 5 seconds. Placed after this call it immediatly breaks. Is there anything special about this call I have to consider with multiple OpenGL-contexts?