我正在做一个用OpenGL显示视频流的项目,然后在外部屏幕上显示QOpenGLWidget上的内容。因此,我所做的是在OpenGL小部件上显示流,然后使用带有两个Pixel缓冲区对象的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,要么我没有正确地理解我应该使用它们的情况。
谢谢
发布于 2016-08-18 19:59:14
您对Pixel缓冲区对象的用途有一个大致的理解(我认为),通过在两个不同缓冲区之间的每一个帧进行乒乓来演示。真正的问题是,两个像素缓冲区可能不足以防止管道停滞。
许多驱动程序被配置为对三个帧排队命令,如果您试图在frame n期间读取frame n+2的结果,则有效地缩短了最大管道深度。框架n+2的命令设置将不被允许继续进行,直到n完成并读取的结果。
驱动程序的命令队列行为远远超出了OpenGL的范围,您将永远无法知道驱动程序预先设置了多少帧。将读取之间的时间增加到3会有帮助,但理想情况下,您想要使用的是一个栅栏同步。
您可以将一个同步对象插入到OpenGL中的命令流中,其唯一目的是在某个点之前的所有命令完成后发出信号。检查此对象的信号状态不会以任何方式拖住管道,并允许您快速判断来自上一帧的命令何时在GPU上完成,并且像素缓冲区的读取不会带来任何CPU/GPU同步问题。
https://stackoverflow.com/questions/39013293
复制相似问题