1

我有一组使用 openGL 的 PBO 概念显示的 RGB 帧。下面是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include "glew.h"
#include "glfw.h"
#include "glaux.h"
#include "logodata.h"

PFNGLGENBUFFERSARBPROC pglGenBuffersARB = 0;                     // VBO Name Generation Procedure
PFNGLBINDBUFFERARBPROC pglBindBufferARB = 0;                     // VBO Bind Procedure
PFNGLBUFFERDATAARBPROC pglBufferDataARB = 0;                     // VBO Data Loading Procedure
PFNGLBUFFERSUBDATAARBPROC pglBufferSubDataARB = 0;               // VBO Sub Data Loading Procedure
PFNGLDELETEBUFFERSARBPROC pglDeleteBuffersARB = 0;               // VBO Deletion Procedure
PFNGLGETBUFFERPARAMETERIVARBPROC pglGetBufferParameterivARB = 0; // return various parameters of VBO
PFNGLMAPBUFFERARBPROC pglMapBufferARB = 0;                       // map VBO procedure
PFNGLUNMAPBUFFERARBPROC pglUnmapBufferARB = 0;                   // unmap VBO procedure
#define glGenBuffersARB           pglGenBuffersARB
#define glBindBufferARB           pglBindBufferARB
#define glBufferDataARB           pglBufferDataARB
#define glBufferSubDataARB        pglBufferSubDataARB
#define glDeleteBuffersARB        pglDeleteBuffersARB
#define glGetBufferParameterivARB pglGetBufferParameterivARB
#define glMapBufferARB            pglMapBufferARB
#define glUnmapBufferARB          pglUnmapBufferARB

int index;
int pboSupported;
int pboMode;
GLuint  pixBuffObjs[2];
HDC hDC = NULL;
GLuint  texture;
char *FileName;
unsigned char *guibuffer;
AUX_RGBImageRec texture1;
unsigned long long pos=0;
GLuint myPBO;
GLuint logoPBO;
unsigned char *logoBuff;

void initGL(void)
{
        int maxSz;
        int maxwidth = 416;
        int maxheight = 240;

        if( !glfwInit() )
        {
            exit( EXIT_FAILURE );
        }


        // if( !glfwOpenWindow(4096, 2118, 0,0,0,0,0,0, GLFW_WINDOW ) )
        if( !glfwOpenWindow(maxwidth, maxheight, 0,0,0,0,0,0, GLFW_WINDOW  ) ) //GLFW_FULLSCREEN
        {
            glfwTerminate();
            exit( EXIT_FAILURE );
        }

        glfwSetWindowTitle("sample");

        glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
        glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
        glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
        glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)wglGetProcAddress("glBufferSubDataARB");
        glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
        glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)wglGetProcAddress("glGetBufferParameterivARB");
        glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB");
        glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB");

        // check once again PBO extension
        if(glGenBuffersARB && glBindBufferARB && glBufferDataARB && glBufferSubDataARB &&
           glMapBufferARB && glUnmapBufferARB && glDeleteBuffersARB && glGetBufferParameterivARB)
        {
            pboSupported = 1;
            pboMode = 1;    // using 1 PBO
            printf( "Video card supports GL_ARB_pixel_buffer_object.");
            glGenBuffersARB(1, &pixBuffObjs[0]);
        }
        else
        {
            pboSupported = 0;
            pboMode = 0;    // without PBO
            printf("Video card does NOT support GL_ARB_pixel_buffer_object.");
        }

        glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxSz);

        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);       // This Will Clear The Background Color To Black
        glClearDepth(1.0);                          // Enables Clearing Of The Depth Buffer
        glDepthFunc(GL_LESS);                       // The Type Of Depth Test To Do
        glEnable(GL_DEPTH_TEST);                    // Enables Depth Testing
        glShadeModel(GL_SMOOTH);                    // Enables Smooth Color Shading


        glMatrixMode(GL_PROJECTION);
        //glLoadIdentity();



        hDC= wglGetCurrentDC();
#if 1
        { // TSS
            HWND hCurrentWindow = GetActiveWindow();
            char szTitle[256]="sample";
            //SetWindowText(hCurrentWindow, );
            // SetWindowLongA (hCurrentWindow , GWL_STYLE, (GetWindowLongA (hCurrentWindow , GWL_STYLE) & ~(WS_CAPTION)));
            SetWindowLongA (hCurrentWindow, GWL_STYLE, (WS_VISIBLE));
        }
#endif
        glEnable(GL_TEXTURE_2D);
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);

}

int GL_Disply()
{
    FILE *fptr=fopen("F:\\myRGBvideo.rgb","rb");
    fseek(fptr,pos,SEEK_SET);
    fread(guibuffer,sizeof(unsigned char),sizeof(unsigned char)*416*240*3,fptr);
    pos+=416*240*3;
    texture1.sizeX =416;
    texture1.sizeY =240;
    texture1.data = guibuffer;

    glDepthFunc(GL_ALWAYS);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glDisable(GL_LIGHTING);

    //glEnable(GL_TEXTURE_2D);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
#if 0
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture1.sizeX, texture1.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, guibuffer);
#else
    glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, myPBO);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture1.sizeX, texture1.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
#endif

    glBegin(GL_QUADS);

    //glNormal3f( 0.0f, 0.0f, 0.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f,  0.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f,  0.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  0.0f);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  0.0f);

    glEnd();

    //disp logo
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, LOGO_WIDTH, LOGO_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, logoBuff);

    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(0.8f,  0.8f,  0.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.97f,  0.8f,  0.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.97f, 0.97f,  0.0f);
    glTexCoord2f(0.0f, 0.0f);glVertex3f(0.8f, 0.97f,  0.0f);
    glEnd();

    glDisable(GL_BLEND); 
    glEnable(GL_DEPTH_TEST);

    // Swap front and back rendering buffers
    glfwSwapBuffers();
    //glDeleteTextures(1, &texture);
    fclose(fptr);

}
int main(int argc, char *argv[])
{
    initGL(); // GL initialization

#if 0
    /* CPU memory allocation using C - malloc */
    guibuffer=(unsigned char*)malloc(sizeof(unsigned char)*416*240*3);
#else
    /*GPU memory allocation using C*/
    glGenBuffersARB(1, &myPBO);
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, myPBO);
    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 416*240*3, NULL, GL_STREAM_DRAW_ARB);


#endif
        //Allocating memory for RGBA logo data present in logodata.h
    logoBuff=(unsigned char*)malloc(400*312*4*sizeof(unsigned char));
    memcpy(logoBuff,TELLogo_RGB,400*312*4);
    for(index=0;index<200;index++)
    {
        guibuffer=(unsigned char*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB);
        glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

        printf("frame %d displayed\r",index);
        GL_Disply();

    }
    free(logoBuff);
    return 0;
}

当上面的代码在具有下面列出的显卡详细信息的系统上运行时,显示是正常的并且工作正常:

第一系统:

Graphics card: Nvidia GEForce 580
OpenGL Version: 4.3

第二系统:

Graphics card: NVidia GEForce 310
OpenGL Version: 3.3

第三系统:

Graphics card: MSI
OpenGL Version: 4.2

但是,当相同的代码在我的笔记本电脑上运行相同的系统配置但图形卡详细信息如下所示时,对于某些流(某些流工作正常),我会得到一种混蛋(轻微卡住)。我在上面列出的不同系统上检查了相同的流,它们似乎工作正常。

Graphics card: Intel HD Graphics 4000
openGL Version: 4.0

导致此问题的问题可能是什么?

4

2 回答 2

4

你的代码被严重破坏了。如果它完全有效,那么不仅仅是偶然:

for(index=0;index<200;index++)
{
    guibuffer=(unsigned char*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB);
    glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

    printf("frame %d displayed\r",index);
    GL_Disply();

}

然后您的代码写入guibufferin GL_Display,然后尝试获取 PBO 中的数据以进行纹理更新。

您必须知道,在 之后glUnmapBufferARB(),您通过映射获得的指针变得无效。写入它只是未定义的行为。您可能在这里很幸运,因为 nvidia 驱动程序可能会使用一些客户端内存作为缓冲区,并且指针意外地继续指向真正的缓冲区 - 但这或多或少是一个模糊的巧合。请注意,您也不能只保留一直映射的缓冲区,因为当它被映射时,您不能使用 GL 对象。至少在没有全新的GL_ARB_BUFFER_STORAGE 扩展(自 4.4 以来的核心)的情况下并非如此,即使在那里,您也必须手动同步客户端和 GL 的访问 - 无论如何,根本问题将保持不变。

要做到这一点,最简单的解决方案是每帧执行以下操作:映射缓冲区,将文件读入 int,取消映射,更新纹理,绘制。

但是,这可能会比完全不使用 PBO 快一点,但性能不会是最佳的。您可以通过在映射之前孤立缓冲区来改善这一点。它会告诉 GL 您不再关心缓冲区的内容(当然,所有处理此数据的挂起的 GL 操作都将完成)并允许 GL 立即提供新的存储,而旧的缓冲区内容只要需要,就可以在内部使用。要进行孤立,只需使用glBufferData()正确的大小并NULL再次用作数据指针。也可以使用设置了访问位的更现代(并且实际上是首选)glMapBufferRange()功能来完成孤立。GL_MAP_INVALIDATE_BUFFER_BIT有关详细信息,请参阅GL_MAP_BUFFER_RANGE 扩展

完全异步资源更新的另一种解决方案是使用PBO,这样您就可以将下一帧上传到另一个 PBO,而 GPU 仍在从当前 PBO 获取数据。这基本上会像孤立方法一样工作,但对 GL 的压力更小,尤其是它的缓冲区管理,因此可以预期更少的开销(尽管它不太可能与您的用例相关)。

除了您的 PBO 逻辑中的缺陷之外,我还想提一下其他几点:

  1. 您正在使用GL_ELEMENT_ARRAY_BUFFER. 稍后将此缓冲区用作 是完全合法的GL_PIXEL_UNPACK_BUFFER,但 GL 可能会使用此信息来优化预期的使用(特别是通过选择缓冲区在 VRAM 或客户端内存中的位置)。
  2. 您将缓冲区映射到GL_READ_WRITEwhereGL_WRITE_ONLY就足够了,并且可能是更有效的路径(实际上是建议的孤立 via 所必需的glMapBufferRange
  3. 正如 datenwolf 在另一个答案中已经指出的那样,使用glTexSubImage2D()而不是glTexImage2D()纹理更新。
于 2013-12-31T14:41:50.670 回答
3

在您调用的显示功能glTexImage2D中。此函数执行完整的纹理对象重新/分配。根据驱动程序的实现细节,如果随着时间的推移积累了太多纹理对象,这可能会触发内部垃圾收集。由于您的意图是显示格式和大小相同的帧流,因此您应该只使用替换纹理数据glTexSubImage2D

只需调用glTexImage2D一次即可初始化纹理对象,然后用于glTexSubImage2D上传新数据。为了使编码更容易初始化纹理对象,glTexImage2D方法是在未绑定 PBO 时使用数据参数的空指针调用。

于 2013-12-31T09:42:23.157 回答