Qt/OpenGL:我正确使用PBO吗?

Qt/OpenGL : Am I using PBO correctly ?

本文关键字:PBO OpenGL Qt      更新时间:2023-10-16

我正在做一个项目,用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只是一个布尔值,用于在第一个和第二个PBO之间切换值。

显然,因为我的性能下降,我做错了什么?我使用pbo的方式不对,或者我没有正确理解我应该使用它们的情况。

谢谢

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

许多驱动程序都被配置为为三个帧排队命令,如果你试图在n+2帧期间读回n帧的结果,你就有效地缩短了最大管道深度。n+2帧的命令设置将不允许继续,直到n的结果完成并被读取。

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

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