2016-08-18 117 views
0

我正在开发一个项目,用OpenGL显示视频流,然后在外部屏幕上显示QOpenGLWidget上的内容。所以我做的是在OpenGL小部件上显示流,然后使用glReadPixels和两个像素包缓冲区对象来获取缓冲区并将其发送到另一个屏幕。问题是,与使用PBOs时相比,当我不是时,我会失去表现。Qt/OpenGL:我是否正确使用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之间交替一个布尔值。

显然,由于我失去表现,我做错了什么?我是以错误的方式使用公益组织,或者我没有正确理解我应该使用它们的情况。

感谢

回答

2

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

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

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

您可以在OpenGL中的命令流中插入一个同步对象,其唯一目的是一旦所有命令完成后都会发出信号。检查此对象的信号状态不会以任何方式拖延流水线,并且可以让您快速判断GPU上前一帧的命令何时完成,并且像素缓冲区的回读不会引入任何CPU/GPU同步问题。

+1

当然,如果你天真地增加缓冲区长度,会引入额外的延迟。一些API(例如Direct3D)使用FIFO队列来呈现帧渲染,这为队列中的每个缓冲区添加了1帧的延迟(在移到下一帧之前,必须显示每帧)。绝对不要将此设计用于视频应用,请放下晚期帧。 –