我希望将我的计算内容放在辅助线程中,同时将主循环保留在主线程中

时间:2013-09-13 00:45:35

标签: c++ multithreading opengl boost glut

我希望将计算内容放在辅助线程中,同时将主循环保留在主线程中。

例如,我想要一个围绕OY旋转的立方体,并改变纹理。旋转摄像机的 空闲 功能支持立方体旋转。但我的纹理计算太复杂,需要一些时间,所以我不能把它们放入 空闲 (每次我的立方体旋转时我都不需要改变纹理)。我可以使用 foo 函数执行一些计算工作,创建纹素缓冲区并在单独的线程中为多维数据集设置新纹理吗? 来自 功能的这段代码不会改变旋转立方体的纹理。

glutIdleFunc(idle);
boost::thread_group tgroup;
tgroup.create_thread(boost::bind(&foo));
glutMainLoop();
tgroup.join_all();

在不同的线程中设置新纹理也存在并发问题吗?

3 个答案:

答案 0 :(得分:5)

虽然不可能一次从多个线程调用给定上下文的OpenGL操作,但可以使用映射的PBO将纹理缓冲区操作卸载到另一个线程。

在您的(主)OpenGL线程中,为纹理数据分配一个具有正确大小的像素缓冲区对象(PBO),并将其映射到进程内存中。在这种情况下的使用模式是,PBO作为数据的短期中介,即上传到该缓冲区,然后是对该缓冲区的OpenGL访问,然后是缓冲区删除或数据改变;这是STREAM使用模式。

GLuint pboID;
glGenBuffers(1, &pboID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboID);
glBufferData(GL_PIXEL_UNPACk_BUFFER, size, NULL, GL_STREAM_DRAW);
void *buffermap = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
glBindBuffer(GL_PIXEL_UNPACk_BUFFER, 0); /* the memory mapping is preserved */

/* queue that pbo for the worker thread to work upon */

您现在可以将值写入buffermap指向的内存区域;每个线程都可以做到这一点完成更新缓冲区后,取消映射并使用它将数据加载到纹理中。当绑定像素解包缓冲区时,glTex[Sub]Image的数据参数变为基于0的偏移参数,指定缓冲区对象中的偏移位置,从中获取数据。

if( workerthread_is_done ) {
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboID);
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);

    /* prepare a texture object as usual */
    glTex[Sub]Image2D(…, NULL);

    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}

您现在可以删除PBO pboID ,也可以通过向其提供新数据来重复使用它。

答案 1 :(得分:3)

一般来说,你不能从多个线程调用OpenGL函数(不使用多个渲染上下文或上下文切换)。

您必须有一个绑定的渲染上下文来发出OpenGL命令,并且窗口系统会将您限制为每个线程的单个上下文。要解决这个问题,您需要使用比GLUT更先进的框架。基本思想是你需要在上下文之间共享资源,一个用于上传数据,一个用于实际渲染。

但是我想的越多,你就没有真正的理由去做。坚持为所有GL命令使用单个线程,可能在另一个线程中从磁盘加载图像文件。并通知您渲染的线程,使用glTexImage2D (...)将数据发送到GL。说实话,你的用例并不复杂,不足以保证多线程渲染。

答案 2 :(得分:0)

你不能多线程OpenGL调用。但是,如果您愿意,您可以在不使用OpenGL代码的情况下预先计算纹理计算,然后将结果放入主线程中以供OpenGL使用。