不理解为什么 win32 api 和 OpenGL 和 wgl 的上下文创建失败

Not understanding why context creation failing with win32 api and OpenGL and wgl

所以我遵循了 windows 创建 OpenGL 渲染上下文

中的所有基本说明

问题是当我尝试使用 opengl 创建核心配置文件上下文时,它失败了,当我 运行 [=] 时,我从 windows 收到 "the program stopped working" 消息36=] 文件,没有迹象表明问题存在于何处以及导致问题的原因,我什至尝试 运行 gdb 但它仅指函数

wglCreateContextAttribsARB 且未提供其他信息

这是我的文件,目前包含在程序中

mainWin.c

#include "mainWin.h"
#include "glPart.c"



//main function, point of entry for windows application 
//must be present in a windows application

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
               LPSTR lpCmdLine, int nCmdShow)
{
   MSG        Msg;  //variable for storing messages retrieved from operating system by using GetMessage
   HWND       hWnd;
   WNDCLASS   WndCls;

   // Create the window object
   //sends a WM_CREATE message to windows which doesnt get processed until you retrieve messages and process them 

   //initialize window class must be initialized no default class 
   initWinClass(&WndCls, hInstance);
   //Register the application must register application to make it available to other controls 
   RegisterClass(&WndCls);

   hWnd = CreateWindow(ClsName,
                       WndName,
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       640,
                       640,
                       NULL,
                       NULL,
                       hInstance,
                       NULL);

   //printf("at initialization %x\n",hWnd);

   // Find out if the window was created
   if( !hWnd ) // If the window was not created,
      return 0; // stop the application

   printf("Window was created....\n");   

   // Display the window to the user
   ShowWindow(hWnd, SW_SHOWNORMAL);
   UpdateWindow(hWnd);

   initGL(hDC);

   //GLint a, b;

   while (Msg.message != WM_QUIT)
   {
      while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
      {
          TranslateMessage (&Msg);
          DispatchMessage (&Msg);
      }
     //Here is were all the "animation that isn't used when the user does something" code will go.
      renderTri();
      SwapBuffers(hDC);
   }

   return Msg.wParam;
}

winMain.h

#define true 1
#define false 0

#include <windows.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/gl.h>

LPCTSTR ClsName = "OpenGL App";
LPCTSTR WndName = "My Game";
//global hdc
HDC hDC;

PIXELFORMATDESCRIPTOR pfd = {
      sizeof(PIXELFORMATDESCRIPTOR),          //size of structure
      1,                                      //default version
      PFD_DRAW_TO_WINDOW |                    //window drawing support
      PFD_SUPPORT_OPENGL |                    //opengl support
      PFD_DOUBLEBUFFER,                       //double buffering support
      PFD_TYPE_RGBA,                          //RGBA color mode
      32,                                     //32 bit color mode
      0, 0, 0, 0, 0, 0,                       //ignore color bits
      0,                                      //no alpha buffer
      0,                                      //ignore shift bit
      0,                                      //no accumulation buffer
      0, 0, 0, 0,                             //ignore accumulation bits
      24,                                     //16 bit z-buffer size
      8,                                      //stencil buffer
      0,                                      //no aux buffer
      PFD_MAIN_PLANE,                         //main drawing plane
      0,                                      //reserved
      0, 0, 0 };                              //layer masks ignored

//context attributes
int attribs[] =
{
   WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
   WGL_CONTEXT_MINOR_VERSION_ARB, 1,
   WGL_CONTEXT_FLAGS_ARB, 0,
   WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 
   0
};


LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void initWinClass(PWNDCLASS WndCls, HINSTANCE hInstance){

   // Create the application window
   //WndCls.cbSize        = sizeof(WNDCLASSEX); wndclassex
   WndCls->style         = CS_HREDRAW | CS_VREDRAW |CS_OWNDC;  
   //the style member variable specifies the primary operations applied on the window class
   //if user moves or changes its size, you would need the window redrawn to get its characteristics 
   //CS_HREDRAW CS_VREDRAW draw the window vertically and horizontally  
   WndCls->lpfnWndProc   = WndProcedure;
   WndCls->cbClsExtra    = 0;
   WndCls->cbWndExtra    = 0;
   WndCls->hIcon         = LoadIcon(NULL, IDI_APPLICATION);
   WndCls->hCursor       = LoadCursor(NULL, IDC_ARROW);
   WndCls->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //cast to HBRUSH 
   WndCls->lpszMenuName  = NULL;
   WndCls->lpszClassName = ClsName;
   WndCls->hInstance     = hInstance;
   //WndCls.hIconSm       = LoadIcon(NULL, IDI_APPLICATION); wndclassex

}

void setupPixelFormat(HDC hDC){

   int nPixelFormat;

   /*      Choose best matching format*/
   nPixelFormat = ChoosePixelFormat(hDC, &pfd);

   if (nPixelFormat == 0) printf("Error in choose pixel format\n");

   /*      Set the pixel format to the device context*/
   BOOL bResult = SetPixelFormat(hDC, nPixelFormat, &pfd);

   if (!bResult) printf("Error in set pixel format\n");


}

void setupPixelFormatARB(HDC hDC){

   const int attribList[] =
   {
     WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
     WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
     WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
     WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
     WGL_COLOR_BITS_ARB, 32,
     WGL_DEPTH_BITS_ARB, 24,
     WGL_STENCIL_BITS_ARB, 8,
     0,        //End
   };

   int pixelFormat;
   UINT numFormats;

   wglChoosePixelFormatARB(hDC, attribList, NULL, 1, &pixelFormat, &numFormats);
   SetPixelFormat(hDC, pixelFormat, &pfd);


}

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
   //printf("the message %d memory address is %x\n", Msg, hWnd);   

   static HGLRC hRC;

    switch(Msg)
    {
    //this is the favourite message you can use to perform any early processing that you want to make 
    //sure happens before most things show up you can use this message to initialize anything in your application
    //The window procedure of the new window receives this message after the window is created, 
    //but before the window becomes visible.
    //will only run once on creation
    case WM_CREATE:
       hDC = GetDC(hWnd);   //get the device context for window
       setupPixelFormat(hDC); //call our pixel format setup function

       //in order to use ARB context creation you must create a render context
       //must be made active and destroyed 
       HGLRC tempContext = wglCreateContext(hDC);
       wglMakeCurrent(hDC, tempContext);

       hRC = wglCreateContextAttribsARB(hDC,0, attribs);
       wglMakeCurrent(NULL, NULL);
       wglDeleteContext(tempContext);
       wglMakeCurrent(hDC, hRC);

      wglMakeCurrent(hDC,hRC);  //make rendering context current old style
    break;

    //minimum application needs to deal with: 
    //wm_destroy message to close window and default case for non registered default messaging processing
    //otherwise hanging or not reaching event queue  

    case WM_DESTROY: //Sent when a window is being destroyed. 
                     //It is sent to the window procedure of the window being destroyed after the window is removed from the screen.
    //you can use this message to deconstruct the window once the user requests to destroy the window
       wglMakeCurrent(hDC,NULL);    //deselect rendering context
       wglDeleteContext(hRC);       //delete rendering context
       PostQuitMessage(0);      //The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately
       //send wm_quit message 
       //Indicates a request to terminate an application, and is generated when the application calls the PostQuitMessage function. 
       //This message causes the GetMessage function to return zero.
       printf("Window destroyed goodbye...bye");
    break;

    //this must exist to process left over messages or the application will hang or will not go forward through the 
    //event queue and the while loop will 
    default:
        // Process the left-over messages and messages that are not dealt with
       return DefWindowProc(hWnd, Msg, wParam, lParam);
    break;
    }
    // If something was not done, let it go
    return 0;
}

最后 glPart.c

#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>

void initGL(HDC hDC){

   //set experimental value to true so that all functions can be used
       glewExperimental = GL_TRUE;

       //initialize glew and get result , check result is not a failure 
       GLenum err = glewInit();
       if(err!=GLEW_OK){
          printf("glew failed!!!....");     
       }

   //wglGetProcAddress("wglGetExtensionsStringARB")

   printf("OpenGL version string is %s\n", glGetString(GL_VERSION));

   GLint OpenGLVersion[3];

   glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
   glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);

   printf("Glew version is %s\n", glewGetString(GLEW_VERSION));
   printf("GL Major version %d\nGL Minor Version %d\n", OpenGLVersion[0], OpenGLVersion[1]);
   printf("GLSL version is %s \nVendor of OpenGL is %s \nRenderer version is %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION), 
                                                                                    glGetString(GL_VENDOR) ,glGetString(GL_RENDERER));
   // Enable settings 
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}
void renderTri(){

   //finally some drawing OpenGL

   GLuint vao;
   glGenVertexArrays(1, &vao);
   glBindVertexArray(vao);

   // An array of 3 vectors which represents 3 vertices
   static const GLfloat verticies[] = {
     -1.0f, -1.0f, 0.0f,
      1.0f, -1.0f, 0.0f,
      0.0f,  1.0f, 0.0f,
   };

   // This will identify our vertex buffer
   GLuint vbo;
   // Generate 1 buffer, put the resulting identifier in vertexbuffer
   glGenBuffers(1, &vbo);
   // The following commands will talk about our 'vertexbuffer' buffer
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   // Give our vertices to OpenGL.
   glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);

   // 1rst attribute buffer : vertices
   glEnableVertexAttribArray(0);
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   glVertexAttribPointer(
      0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
      3,                  // size
      GL_FLOAT,           // type
      GL_FALSE,           // normalized?
      0,                  // stride
      (void*)0            // array buffer offset
   );
   // Draw the triangle !
   glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
   glDisableVertexAttribArray(0);

}

现在,如果我在没有 wglCreateContextAttribsARB 的情况下以旧方式执行此操作,它工作正常并且即使没有着色器也可以执行它应该执行的操作,但是当我尝试通过使用 wgl 创建核心配置文件上下文来执行此操作时,程序失败

我用

编译
gcc -Wall -Werror mainWin.c -lopengl32 -lglew32 -lgdi32

没有报错

让我们看看您的代码:

case WM_CREATE:
   hDC = GetDC(hWnd);   //get the device context for window
   setupPixelFormat(hDC); //call our pixel format setup function

   //in order to use ARB context creation you must create a render context
   //must be made active and destroyed 
   HGLRC tempContext = wglCreateContext(hDC);
   wglMakeCurrent(hDC, tempContext);

   hRC = wglCreateContextAttribsARB(hDC,0, attribs);
   wglMakeCurrent(NULL, NULL);
   wglDeleteContext(tempContext);
   wglMakeCurrent(hDC, hRC);

   wglMakeCurrent(hDC,hRC);  //make rendering context current old style

您的评论

in order to use ARB context creation you must create a render context must be made active and destroyed

尤其具有误导性。它不是为了自身的缘故而创建和销毁一些遗留上下文。它是关于创建上下文 以获取 WGL 扩展函数指针 ,而您根本不会这样做。

由于你使用的是GLEW的wglew功能,它会在wglew.h中声明所有必要的函数指针,但是这些函数指针都被初始化为NULL,所以你调用wglCreateContextAttribsARB 只会取消引用 NULL 指针并崩溃。

创建遗留 OpewGL 上下文并使其成为当前上下文不会神奇地初始化这些指针。您必须显式调用 wglewInit() 来查询这些函数指针 - 这是您唯一需要 tempContext 处于活动状态的时间。

 //in order to use ARB context creation you must create a render context
 //must be made active and destroyed 

这不是你 create a temporary rendering context 的原因。

在Win32中,您可以直接访问基本的WGL函数。但是 WGL 扩展函数要求您已经有渲染上下文,因为该实现实际上提供了这些扩展。

因此您创建一个临时上下文,然后加载 WGL 扩展,然后销毁临时上下文。

你跳过了中间部分。

此外,Win32 HWND 的像素格式设置不能超过 一次。因为您可能想使用 WGL 扩展来选择像素格式,所以这是个问题。因此,应该为临时 window 创建临时渲染上下文,您可以在其中设置临时像素格式。