VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误

1、问题症状

  在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下:

 OpenGL程序中的0x00000000 处未处理的异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突
void createVBO(GLuint *vbo,int size)
{
  glGenBuffers(1,vbo);//该行代码出错,呜呜
  glBindBuffer(GL_ARRAY_BUFFER,*vbo);
  glBufferData(GL_ARRAY_BUFFER,size,0,GL_DYNAMIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER,0);
  CUT_CHECK_ERROR_GL();
}
是一个建立缓冲区函数的代码,程序编译没有错误,但是运行到glGenBuffers(1,vbo)时,出现标题的错误,如下图所示:

VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误

2、原因分析

  关于缓冲区的一些GL接口,是从GL1.5才开始有的,而windows自带的GL只支持到1.1版本。但如果你的显卡支持GL1.5以上的话,glew就很好的帮你完成了扩展工作,既然你用glew,那么就应该在使用GL任何一个接口前首先调用glewInit来初始化这些扩展,否则那些GL接口都不能使用。在你的init方法开头添加加glewInit就可以了。

3、解决办法

  (1)、Win32工程环境

     先按如下代码初始化

//设置OpenGL环境
void SetupGL(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize (WINDOW_WIDTH, WINDOW_HEIGHT);
    glutCreateWindow(ProgramName);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);

    glewInit();//glew初始化
}    

    然后再调用下面的产生缓冲区标识的代码:

glGenBuffers(1,vbo);//产生缓冲区标识

    (2)、VC++ MFC单文档应用程序SDI下工程环境

    在VC++ MFC单文档应用程序SDI下工程环境下,需要先调用wglMakeCurrent(m_hDC, tempContext);方法,然后再调用glew初始化代码,最后再调用产生缓冲区标识的代码。如果未在wglMakeCurrent之后调用glewInit方法,则会造成glewInit返回1(成功返回0)。从而导致前面的运行时问题出现。下面给出调用次序:

  CRSQuickLookView::OnCreate--_>GLInit()--->GetSafeHdc()--->ChoosePixelFormat(m_hDC, &pfd)--->SetPixelFormat(m_hDC, PixelFormat, &pfd)--->wglCreateContext(m_hDC)--->wglMakeCurrent(m_hDC, g_p00RC)--->glewInit()--->initGLBuffers()--->glGenBuffers(1,vbo)。其中,GLInit()和initGLBuffers()方法具体定义如下:

void CRSQuickLookView::GLInit()
{
    CreateTexturePixel();//产生测试的像素缓冲区数据
    //m_hDC = ::GetDC(m_hWnd);
    CDC* clientDC = new CClientDC(this);
    m_hDC = clientDC->GetSafeHdc();

    if (m_hDC  == NULL)
        return;

    static PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,           //标志
        PFD_TYPE_RGBA,                 //颜色模式
        24,                                   //颜色位数
        0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0,
        32,                                  //深度位数
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };
    GLuint PixelFormat;
    if ((PixelFormat = ChoosePixelFormat(m_hDC, &pfd)) == 0)
        return;                //选择相应像素格式
    if (!SetPixelFormat(m_hDC, PixelFormat, &pfd))
        return;                               //设置像素格式
    //if ((m_hRC = wglCreateContext(m_hDC)) == NULL)
    if ((g_p00RC = wglCreateContext(m_hDC)) == NULL)
        return;                          //创建着色描述表
    SetupCUDA();//设置CUDA环境,主要完成最强计算能力显卡的选择和设置
    //GLSetupRC();
    //if (!wglMakeCurrent(m_hDC, m_hRC)) 
    if (!wglMakeCurrent(m_hDC, g_p00RC))
        return;                                           //将着色描述表连接到设备描述表

    int re=glewInit();
    initGLBuffers();
}
void CRSQuickLookView::initGLBuffers()
{
    // create pixel buffer object to store final image
    glGenBuffers(1, &pbo);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
    glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * sizeof(GLubyte) * 3, pPixelData, GL_DYNAMIC_DRAW);//GL_STREAM_DRAW_ARB
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    checkCudaErrors(cudaGLRegisterBufferObject(pbo));

    // create texture for display
    glGenTextures(1, &_texture);
    glBindTexture(GL_TEXTURE_2D, _texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

参考链接:

1、glewInit初始化的错误glewInit初始化的错误

2、在mfc下使用opengl中的vbo进行绘制,绘制失败

3、OpenGL程序中的0x00000000 处未处理的错误: 0xC0000005: 读取位置 0x00000000 时发生访问冲突

4、glGenBuffersARB 运行时访问冲突

5、OpenGL程序中与glew相关的未处理异常的解决方案