多线程内的OpenGL VBO

时间:2012-01-18 15:44:38

标签: multithreading opengl vbo

我正在用C ++ / OpenGL开发一个程序来绘制整个世界的地形。我有一个海拔高度数据库存储为瓷砖。每次启动程序时,都会加载一个磁贴。然后当人移动时,应该加载另一个图块,这不会发生在每一帧,可能每5分钟一次。

我将初始磁贴加载到视频卡的内存中:

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VertexBuffer[idx]);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, VBOsz * 3 * sizeof(float), tile_data, GL_STATIC_DRAW_ARB);

......有法线,颜色和索引缓冲区

我画了它们:

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VertexBuffer[idx]);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, VBOsz * 3 * sizeof(float), tile_data, GL_STATIC_DRAW_ARB);


glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VertexBuffer[idx]);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

...

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBuffer[idx]);
glDrawElements(GL_TRIANGLES, IndexBuffersz, GL_UNSIGNED_INT, BUFFER_OFFSET(0));

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

由于我希望程序尽可能平滑,我无法计算同一帧的顶点+颜色+法线+其他纹理,因为创建一个图块需要大约20秒。

所以我决定创建一个加载程序线程来检查何时需要加载新的tile,然后加载它。什么时候完成,它应该只是交换VBO(因此[idx]。

所以对于一个加载器线程,我知道我需要第二个OpenGL上下文,我创建了一个,我在它们之间共享列表。这个想法是有效的,但在加载器线程中,当我发送新的VBO数据时,我需要这个函数:wglMakeCurrent

只有在加载了所有数据后,我才能将上下文设置为渲染线程(主程序的线程)。这导致在这段时间内没有任何东西被绘制,这使得程序无用。

您对解决方案有什么想法吗?我需要改变这个概念吗?

我正在使用OpenGL 2.1。升级到OpenGL 3会解决这个问题吗?

2 个答案:

答案 0 :(得分:3)

我已经有answer来处理这类任务。

简而言之,您创建了两个共享上下文。然后,正如 Damon 所建议的那样,将上下文设置为自己的线程,只在线程执行开始时进行一次。这两个上下文将在不同的线程(一个线程,一个上下文)上同时是当前的。

然后,辅助线程不会用于渲染,而是用于加载资源(我的意思是,实际加载地形数据,纹理......并在每个数据上创建相应的OpenGL对象,例如纹理和缓冲区对象) 。这是在主要上下文绘制时发生的。

基本上,您不必担心在应用程序周围添加指针并阻止渲染线程上传数据;但是以创造另一个背景为代价。让驱动程序同步上下文状态:如果它可以顺利执行该操作,您的应用程序将从中受益;至少,你的代码会更干净。

我对该主题的其他贡献:

答案 1 :(得分:2)

您只需在每个帖子中调用wglMakeCurrent一次。这是可靠的,这是我正在做的(虽然使用OpenGL 3.3)。这标记了属于一个线程的一个上下文。它保持这种方式,直到你以不同的方式告诉OpenGL,所以在开始时做一次并忘记(实际上,如果你使用它们在各自的线程中创建上下文,你根本不需要调用它,但是无论如何只是为了100%安全,我更喜欢在开始之前创建所有上下文,它不是那么混乱......)。

顺便说一下,你不必担心函数指针,只需使用你在渲染线程中使用的那个(假设你已经在那里正确初始化了它)。
从技术上讲,使用来自另一个上下文的函数指针是无效的。但是,WGL保证(隐藏在小字体中!)函数指针对于具有相同像素格式的所有上下文都是相同的。因此,你很高兴。

使用单个上下文的替代方法是在呈现线程中glMapBuffer并将指针传递给工作线程。然后,在完成后(例如,发信号通知信号量),glUnmapBuffer,再次在渲染线程中 有些人更喜欢这个,因为它不涉及上下文杂耍,并且可能在一些旧的越野车司机上做得更好。我不喜欢它,因为需要额外的同步。这是一个品味,同样的效果。