OpenGL多线程渲染,以显示间隔

时间:2016-08-19 11:58:19

标签: multithreading c++11 opengl cuda

我需要以恒定的帧速率显示图像,因此我使用两个线程,一个用于使用VSYNC进行渲染,一个用于使用CUDA进行计算,这可能需要很长时间。我希望计算线程在渲染线程间隔中运行(在交换缓冲区之后,在下一帧开始渲染之前)。

我有两个问题:

  1. 如何知道图像何时在屏幕上精确绘制,然后我就可以唤醒撕裂线程。在glutSwapBuffers()之后,图像可能无法实际显示在屏幕上。我还没有找到通知显示完成的API。
  2. 如何在渲染时停止计算线程,我尝试this_thread::yield()但它仍然经常运行计算线程。我不熟悉多线程编程。
  3. 我将C ++ 11用于多线程,CUDA用于计算,OpenGL用于渲染。

    更新

    由于计算需要很长时间,但渲染必须以60Hz执行,所以我必须分成两个线程。

    我刚刚使用condition_variable解决了这个问题,它类似于'生产者 - 消费者'问题。并且不需要知道图像何时在屏幕上实际绘制,你可以让它一直计算,而CUDA计算线程似乎不会在一个GPU中中断OpenGL渲染线程,它们是并行的。

    以下是代码:

    计算线程:

    void update(){
        while(1){
            unique_lock<mutex> locker(buffer_mutex);
            buffCond.wait(locker, []{return !updateFlag;});
            runSolver(d_x);// compute next several images, d_x point to the images buffer       
            updateFlag = true;
            locker.unlock();
            buffCond.notify_one();
        }
    }
    

    渲染线程:

    void render(){
        initGL();
        glutMainLoop();
    }
    void display(){
        if(updateFlag){
            unique_lock<mutex> locker(buffer_mutex);
            updateBuffer(d_x);
            updateFlag = false;
            locker.unlock();
            buffCond.notify_one();
        }
        .../* OpenGL rendering*/
        glutSwapBuffers();
    }
    

1 个答案:

答案 0 :(得分:1)

图形渲染通常从单个线程完成,至少从单个线程一次完成。我相信更精细的细节取决于你的软件堆栈;例如,来自Xlib

  

线程应用程序:虽然Xlib确实尝试支持多线程,但API使这很困难且容易出错。

来自a rather opinionated but informed article的更多信息:

  

[...]但是,大多数现实生活中的程序通过更高级别的库访问Xlib,并且库不会代表它们初始化Xlib线程。今天,大多数具有多个X11连接和多个线程的程序都是错误的。

话虽如此,多线程CUDA应该仍然是一个选项,所以如果用OpenGL完成,一个线程可以进入CUDA。这样CUDA仍然可以在另一个线程渲染最后一帧时取得进展,但是在延迟下一帧的关键时期,没有线程在等待。当然,如果你真的必须在渲染每个帧之前和之后重新加入,那么你只是在没有并发性的情况下自愿承担切换上下文的成本。在这种情况下,不需要线程。

对于线程之间的共享标志,您也可以从阅读文档或<atomic>的一些示例(尤其是atomic_bool)中受益。如果使用正确,它们可以在线程之间安全地发出状态信号,成本非常低