2016-08-18 115 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幀的延遲(在移到下一幀之前,必須顯示每幀)。絕對不要將此設計用於視頻應用,請放下晚期幀。 –