Search code examples
c++windowsglfwhwndglad

How to init glad without the glfw loader (using windows headers)


I'm trying to render to a HWND window using a HGLRC OpenGL rendering context.

I have to initiate the glad but gladLoadGLLoader((GLADloadproc)wglGetProcAddress)) and the gladLoadGL() seems to be failing.

glad OpenGL version : 4.0 core

I've been using the glfwGetProcAdress function until now.

How can I make the gladLoadGLLoader function work? Would it be that I have to indicate the version of the OpenGL to the wglGetProcAddress function or maybe I should use another loader?

Update 1 :

in the gladLoadGLLoader function the problem is (PFNGLGETSTRINGPROC)load("glGetString") returns null

int gladLoadGLLoader(GLADloadproc load) {
    GLVersion.major = 0; GLVersion.minor = 0;
    glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
    
    if(glGetString == NULL) //Returns there (fails)
        return 0;
    
    if(glGetString(GL_VERSION) == NULL) 
        return 0;
    
    find_coreGL();
    load_GL_VERSION_1_0(load);
    load_GL_VERSION_1_1(load);
    load_GL_VERSION_1_2(load);
    load_GL_VERSION_1_3(load);
    load_GL_VERSION_1_4(load);
    load_GL_VERSION_1_5(load);
    load_GL_VERSION_2_0(load);
    load_GL_VERSION_2_1(load);
    load_GL_VERSION_3_0(load);
    load_GL_VERSION_3_1(load);
    load_GL_VERSION_3_2(load);
    load_GL_VERSION_3_3(load);


    if (!find_extensionsGL()) return 0;
    return GLVersion.major != 0 || GLVersion.minor != 0;
}

Update 2 :

The problem seems to be that wglGetProcAddress is being used to load core OpenGL functions. However, wglGetProcAddress can only load specific WGL extensions and not core OpenGL stuff.

Update 3 :

As an additional note to the update 2, it seems that the GLFW library also uses wglGetProcAddress for the glfwGetProcAddress function

Solved :

void *GetAnyGLFuncAddress(const char *name)
{
  void *p = (void *)wglGetProcAddress(name);
  if(p == 0 ||
    (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
    (p == (void*)-1) )
  {
    HMODULE module = LoadLibraryA("opengl32.dll");
    p = (void *)GetProcAddress(module, name);
  }

  return p;
}

void Renderer::initGlad(){
    //Init GLAD
    if (!gladLoadGLLoader((GLADloadproc)GetAnyGLFuncAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
    }    
}

Replacing wglGetProcAddress with the void *GetAnyGLFuncAddress(const char *name) function solves the problem.


Solution

  • "The problem seems to be that wglGetProcAddress is being used to load core OpenGL functions. However, wglGetProcAddress can only load specific WGL extensions and not core OpenGL stuff." Indeed, wglGetProcAddress does have limitations. But it can load OpenGL functions - in fact, most all of them. The restriction is on loading extremely old GL functions that date back to OpenGL 1.1. This is the reason why glGetString is null - it's an OpenGL 1.1 function, which isn't supported by it.

    Fortunately, these age-old functions are the ones that happen to be directly exported by the Windows libary opengl32.dll itself. Therefore, you can use the Windows function GetProcAddress on opengl32.dll for these functions. However GetProcAddress, of course, does not work on newer GL functions.

    But we can create a new function to 'bridge the gap' between these two:

    void *GetAnyGLFuncAddress(const char *name)
    {
      void *p = (void *)wglGetProcAddress(name); // load newer functions via wglGetProcAddress
      if(p == 0 ||
        (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
        (p == (void*)-1) ) // does it return NULL - i.e. is the function not found?
      {
        // could be an OpenGL 1.1 function
        HMODULE module = LoadLibraryA("opengl32.dll"); 
        p = (void *)GetProcAddress(module, name); // then import directly from GL lib
      }
    
      return p;
    }
    

    This function, as you can see, first calls wglGetProcAddress, which works for OpenGL 1.1+ functions. Next, it determines if p is null, meaning that this function call was not successful. Then it attempts to call GetProcAddress, working for GL1.1 functions.

    Then, it's simply a matter of calling gladLoadGLLoader((GLADloadproc)GetAnyGLFuncAddress)).


    In practice, it is not neccessary to implement such a function yourself. GLAD has the inbuilt function, gladLoadGL, which if you look at the code, calls gladLoadGLLoader for the internal get_proc function. The code in this function does exactly what we've implemented (removing the #if/#endifs for other OSes):

    void* get_proc(const char *namez) {
        void* result = NULL;
        if(libGL == NULL) return NULL;
        if(gladGetProcAddressPtr != NULL) {
            result = gladGetProcAddressPtr(namez); // essentially wglGetProcAddress - see glad's internal open_gl()
        }
        if(result == NULL) {
            result = (void*)GetProcAddress((HMODULE) libGL, namez);
        }
        return result;
    }
    

    It tries to load the OpenGL function via wglGetProcAddress, and then if that fails, uses GetProcAddress. Therefore, you can just call gladLoadGL.


    The wiki page Load OpenGL Functions has a lot of info on this.