多线程内的OpenGL VBO

Tib*_*ibi 5 opengl multithreading 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);
Run Code Online (Sandbox Code Playgroud)

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

我画它们:

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));
Run Code Online (Sandbox Code Playgroud)

...

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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

Nic*_*las 7

这真的不是那么复杂.

您只需创建两个缓冲区对象:一个用于当前渲染,另一个用于将来使用.当未使用的缓冲区充满数据时,渲染线程切换到从该缓冲区渲染.先前使用的缓冲区变为未使用的缓冲区.

您可以通过以下两种方式之一上传数据.一种方法是让数据创建线程创建一个数据数组,渲染线程将上传到缓冲区对象glBufferData.显然,这需要一些同步,但它是您需要的同步代码:当数据准备好时,最终必须通知您的渲染线程,以便它可以使用新数据进行渲染.

另一种方法是告诉您的渲染线程需要开始生成数据.此时,它将映射未使用的缓冲区对象,并将映射的指针传递给数据创建线程.该线程将直接生成数据到该映射指针.完成后,它会通知渲染线程,它将取消映射缓冲区,然后使用数据进行渲染.

这两种方法都不需要多个上下文或通过OpenGL代码进行线程化.

请注意,不要使缓冲区越来越大,性能最佳.挑一个尺码并坚持下去; 你不想用缓冲区来调整缓冲区glBufferData.


Luc*_*uca 5

我已经有此类任务的答案。

简而言之,您创建了两个共享上下文。然后,按照Damon的建议,使上下文在其自己的线程上成为当前上下文,仅在线程执行开始时一次。两个上下文将同时在不同线程上处于当前状态(一个线程,一个上下文)。

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

本质上,您无需担心在应用程序中引入指针并阻塞渲染线程上传数据;但以创建另一个上下文为代价。让驱动程序同步上下文状态:如果它可以顺利地执行该操作,您的应用程序将从中受益;至少,你的代码会更干净。

我在该主题上的其他贡献: