c++ - Qt/OpenGL : Am I using PBO correctly ?

标签 c++ qt opengl

我正在做一个项目,用 OpenGL 显示视频流,然后在外部屏幕上显示 QOpenGLWidget 上的内容。所以我所做的是在 OpenGL 小部件上显示流,然后我使用 glReadPixels 和两个像素包缓冲区对象来获取缓冲区并将其发送到另一个屏幕。问题是,与不使用 PBO 时相比,我在使用 PBO 时性能下降。

这是代码中有趣的部分:

创建要在外部屏幕上发送的帧的代码:

screenBuffer 是一个内存缓冲区,用于存储来自 QOpenGLWidget

的帧

此时在代码中,PBO 已经填充了来自paintGL 函数的数据

void GLWidget::videodisplay(unsigned char *copy){

    update();

    unsigned char* frame = publicCreateOutputVideoFrame();

    if(pboIndex){

        pbo1->bind();
        pbo1->read(0, screenBuffer, vWidth*vHeight*3);

    }else{

        pbo2->bind();
        pbo2->read(0, screenBuffer, vWidth*vHeight*3);

    }

    pboIndex = !pboIndex;

    unsigned char* yuvFrame = convertRGBtoYUV(screenBuffer);

    memcpy(frame, yuvFrame, vWidth*vHeight*2);

    publicDisplayVideoFrameSync();

    delete yuvFrame;
    yuvFrame = NULL;

    delete copy;
    copy = NULL;

}

PBO 的初始化:

void GLWidget::InitializeGL(){

    pbo1 = new QOpenGLBuffer(QOpenGLBuffer::PixelPackBuffer);
    pbo1->create();
    pbo1->bind();
    pbo1->allocate(vWidth*vHeight*3);
    pbo1->release();

    pbo2 = new QOpenGLBuffer(QOpenGLBuffer::PixelPackBuffer);
    pbo2->create();
    pbo2->bind();
    pbo2->allocate(vWidth*vHeight*3);
    pbo2->release();

}

这里我使用 PBO 和 glReadPixels

void GLWidget::paintGL(){


    glClear(GL_COLOR_BUFFER_BIT);

    program->bind();
    {
        vao.bind();

            glBindTexture(GL_TEXTURE_2D, tex);

                glDrawArrays(GL_QUADS, 0, 4);

            glBindTexture(GL_TEXTURE_2D, 0);

        vao.release();
    }
    program->release();

    if(!isZoomed){

        programMouse->bind();
        {
            vaoMouse.bind();

                    glLineWidth(2.0);
                    glDrawArrays(GL_LINES, 0, 8);

            vaoMouse.release();
        }
        programMouse->release();

    }

    if(pboIndex){

        pbo2->bind();

    }else{

        pbo1->bind();
    }

            glReadPixels(0, 0, vWidth, vHeight, GL_RGB, GL_UNSIGNED_BYTE, 0);

    if(pboIndex){

        pbo2->release();

    }else{

        pbo1->release();
    }



}

pboIndex 只是一个 bool 值,用于在第一个和第二个 PBO 之间切换值。

显然,由于我正在失去性能,所以我做错了什么?我要么以错误的方式使用 PBO,要么我没有正确理解我应该使用它们的情况。

谢谢

最佳答案

您对像素缓冲区对象背后的目的有一个大致的了解(我认为),通过两个不同缓冲区之间的每一帧的乒乓来证明。真正的问题是两个像素缓冲区可能不足以防止管道停顿。

如果您尝试在帧 n+2 期间回读帧 n 的结果,许多驱动程序开箱即用地配置为排队三个帧的命令您已经有效地缩短了最大管道深度。在 n 的结果完成并被回读之前,不允许继续为帧 n+2 设置命令。

驱动程序的命令排队行为远远超出了 OpenGL 的范围,您永远无法知道驱动程序设置为提前工作多少帧。将回读之间的时间长度增加到 3 会有所帮助,但理想情况下您要使用的是 fence sync。 .

您可以在 OpenGL 的命令流中插入一个同步对象,它的唯一目的是在所有命令到某一点完成后发出信号。检查此对象的信号状态不会以任何方式停止管道,并允许您快速判断前一帧的命令何时在 GPU 上完成,并且像素缓冲区的回读不会引入任何 CPU/GPU 同步问题。

关于c++ - Qt/OpenGL : Am I using PBO correctly ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39013293/

相关文章:

opengl - 如何将 SCNScene 渲染到纹理

c++ - std::map 使用 STL::map 旋转方法或算法

c++ - 在特定时间更改 QLabel 的背景颜色

c++ - 文件名、目录名或卷标语法是来自 qt creator c++ 的不正确系统调用

qt - 如何定义qml GroupBox标题样式

c++ - 渲染时加载纹理 (OpenGL)

c# - 覆盖基类方法

c++ - C++ 中接受 2D 数组、将其乘以整数并返回新的 2D 数组的函数?

c++ - 如何让 `static_assert` 打印失败时得到的值?

c++ - glBlitFramebuffer 无效操作