我想在主程序显示加载屏幕时在单独的线程中加载一些纹理和网格,因为加载所有资源需要几秒钟。我正在使用OpenGL和GLFW。我尝试使用以下代码完成此任务:
void *status;
if(pthread_create(&loader, NULL, &loader_func, NULL))
{
fprintf(stderr, "Error creating loader thread\n");
return 1;
}
while(_flags & FLAG_LOADING)
{
vec3 color = { 0.1, 0.3, 1.0 };
if(glfwWindowShouldClose(window))
{
resource_destroy();
glfwTerminate();
return 0;
}
GL_CHECK(glClearColor(0.1, 0.1, 0.1, 1.0));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
font_renderer_activate();
render_string(&_font_menu, "Loading...", _width / 2, _height / 2, 64,
color, ALIGN_V_CENTER | ALIGN_H_CENTER);
glfwSwapBuffers(window);
glfwPollEvents();
}
if(pthread_join(loader, &status))
{
fprintf(stderr, "Error joining loader and main thread\n");
return 1;
}
if(*(int *)status)
{
fprintf(stderr, "Error loading resources\n");
return 1;
}
loader_func()不会呈现到屏幕,仅使用OpenGL函数创建VAO,VBO等并将数据加载到其中。
问题是,在屏幕上显示加载文本并完成加载后,屏幕上什么都没有显示(编辑:除了文本HUD),并且我的日志中收到很多调试错误消息(将所有OpenGL调用包装在一个宏中,该宏使用glGetError检查错误):
main.c:588
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap_texture);
GL_Error 0x502: GL_INVALID_OPERATION
main.c:589
glDrawArrays(GL_TRIANGLES, OFFSET_SKYBOX, VERTICES_SKYBOX);
GL_Error 0x502: GL_INVALID_OPERATION
main.c:629
glDrawArrays(GL_TRIANGLES, OFFSET_SELECTOR, VERTICES_SELECTOR);
GL_Error 0x502: GL_INVALID_OPERATION
当我直接调用loader_func时,没有错误,主渲染循环正常工作。
我读到要在另一个线程中使用OpenGL函数,必须调用glfwMakeContextCurrent
,但是在我的情况下这是行不通的,因为这样就不会渲染加载屏幕。我唯一的想法是利用第二个库(如SDL)在加载时创建一个窗口,然后销毁它并使用GLFW创建一个新窗口以用于OpenGL。仅使用OpenGL,这就是我想实现的目标吗?
最简单的方法是让主线程创建和管理所有OpenGL对象,而加载线程执行File IO(这是加载最慢的部分)。一旦加载线程完成了加载特定资产的任务,它就可以通过将加载的数据传递到主线程,这可以完成OpenGL的最后一部分。
毕竟,这并不像渲染加载屏幕会浪费大量的性能或其他东西一样,因此在主线程上进行上传的成本将降至最低。这也使您能够执行该加载栏操作,因为您的主线程将经常获取加载过程的结果,因此它随时都知道完成了多少加载。
如果您绝对必须有两个线程都出于某种原因都进行OpenGL调用,那么您还应该有两个OpenGL上下文,每个上下文在不同的线程中是最新的,并且两个上下文彼此共享对象。 GLFW非常乐意提供此if you ask it nicely。照常创建主窗口,然后将GLFW_VISIBLE
提示设置为GLFW_FALSE
,然后创建第二个窗口(具有任意分辨率)。您应该将主窗口作为最后一个参数传递给glfwCreateWindow
,以便两个上下文可以共享对象。然后可以在不同的上下文中将每个窗口设置为当前状态,就可以了。
一个警告。在它们之间共享对象的上下文only share certain objects。纯状态对象不能在上下文之间共享。 VAO是纯状态对象,因此尝试在屏幕外的上下文中创建它们是没有意义的。