FPC - glEnableVertexAttribArray not found in OpenGL32.dll

FPC - glEnableVertexAttribArray not found in OpenGL32.dll

I did the following mini-program to troubleshoot. It runs without errors under Linux.
If I try it with Windows in VB or with wine, I get an error that the entry point of glEnableVertexAttribArray cannot be found in the OpenGL32.dll. glClear works without any problems. If I exclude the line with glEnableVertexAttribArray, the program runs without errors.

One an idea. what could this be?

program project1;

{$IFDEF UNIX}
const
  glLib='GL';
{$ENDIF}

{$IFDEF WINDOWS}
const
  glLib='OpenGL32.dll';
{$ENDIF}

procedure glClear(mask: DWord); stdcall; external glLib;
procedure glEnableVertexAttribArray(index: Integer); cdecl; external glLib;

begin
  glClear(0);
  glEnableVertexAttribArray(0);
end.           

On Windows only function up to OpenGL 1.1 are available for direct linking, all others must be accessed through function pointers loaded via wglGetProcAddress. There are libraries that handle this; see wiki page on loading OpenGL functions for details and wiki page on loading libraries.

If I understood correctly, opengl32.dll is not an ordinary DLL where you can statically integrate everything?
From the looks of it, it’s a really exotic DLL that requires a special routine to get to the rest?
There will be no wglGetProcAddress for free.

When I look at Windows OpenGL examples, I can’t find wglGetProcAddress() anywhere.
Are these calls hidden in glefw3.dll or glut_ext.dll and are e.g. called with glfwInit() in the background?

I don’t know what examples you’ve looked at, but assuming they are not ancient and only use OpenGL 1.1 features they probably used a loading library. GLFW is a library that deals with window system integration, but AFAIK does not do it’s own GL function loading. However, at least in this example they use the GLAD library, see this line.
The 1.x versions of GLAD apparently can be used with Pascal, see here. I don’t know anything about the Pascal ecosystem and cannot say if that is a common approach there or if folks user something else.

I looked in there earlier and the tool was selected. I just noticed one shortcoming. Unfortunately, it has no influence on who you select “Generate a Loader” below. The other checkboxes don’t seem to have any influence either.

So I patched in the following. It works on Linux, but it doesn’t work on Windows.
By running I mean that an entire OpenGL program is running and not just the small experiment like in the first post.

var   LibGL: TLibHandle;

{$IFDEF Linux}
function wglGetProcAddress(proc: PAnsiChar): Pointer;
begin
  Result := GetProcAddress(LibGL, proc);
end;
{$ENDIF}

{$IFDEF Windows}
function wglGetProcAddress(proc: PAnsiChar): Pointer;cdecl  external 'OpenGL32.dll';
{$ENDIF}

procedure Load_GLADE;
var
  adr: Pointer;
begin
adr:=  wglGetProcAddress('glBindBuffer');
//ShowMessage(PtrUInt(adr).ToString);
 {$IFDEF Linux}
  LibGL := LoadLibrary(PAnsiChar('libGL.so.1'));
 {$ENDIF}
 gladLoadGL(@wglGetProcAddress);
end;   

Hmm, wglGetProcAddress only works after you create a valid OpenGL context, did you create one and made it current before calling this code?

Hmm, wglGetProcAddress only works after you create a valid OpenGL context, did you create one and made it current before calling this code?
The context creation must run correctly. Otherwise I wouldn’t get an address back with glBindBuffer.
glClearColor has 0.

  adr1 := wglGetProcAddress('glBindBuffer');    // > 0
  adr2 := wglGetProcAddress('glClearColor');    // = 0   

I suspect it must be in the glad_gl unit, where the same thing is called, which gives me 0.

procedure load_GL_VERSION_1_0(load: TLoadProc);      
...
glClearColor := load('glClearColor');   

If I look more closely, it fails here. It certainly can’t get to glGetString

function gladLoadGL(load: TLoadProc): boolean;
var
  glVersion: pansichar;
begin
  glGetString := load('glGetString');
  if not Assigned(glGetString) then begin
    ShowMessage('null');  // Als Test
    exit(False);
  end;

See the wiki page I linked to earlier:

So the glad generator is working incorrectly?

You could try using the Pascal equivalent of the GetAnyGLFuncAddress function from this wiki page and pass that to GLAD.

I almost managed it, now it seems to work with Windows(wine) and Linux.
But there is always one drawback. As soon as I use WriteLn(‘’); remove, the following error occurs in wine: “056c:err:seh:NtRaiseException Exception frame is not in stack limits => unable to dispatch exception.”
In the VB with Win10, there is a SIGSEV, but that is probably because the VB does not support OpenGL >= 3.3.

// glad_gl.pas
...
var
  LibGL: TLibHandle;

{$IFDEF Linux}
function wglGetProcAddress(proc: pansichar): Pointer;
begin
  Result := GetProcAddress(LibGL, proc);
end;
{$ENDIF}

{$IFDEF Windows}
function wglGetProcAddress(proc: pansichar): Pointer; cdecl external 'OpenGL32.dll';
{$ENDIF}

function LoadProc(proc: pansichar): TLoadProc;
begin
  Result := GetProcAddress(LibGL, proc);
  {$IFDEF Windows}
  {$push}
  {$i-}
  WriteLn('');
  {$pop}
  if @Result = nil then  begin
    Result := wglGetProcAddress(proc);
  end;
  {$ENDIF}
end;

procedure Load_GLADE;
begin
  {$IFDEF Linux}
  LibGL := LoadLibrary(pansichar('libGL.so.1'));
  {$ENDIF}
  {$IFDEF Windows}
  LibGL := LoadLibrary(pansichar('OpenGL32.dll'));
  {$ENDIF}
  gladLoadGL(@LoadProc);
end;

end.                                                    
// Main program:
  OpenGLControl1.MakeCurrent;
  Load_GLADE;

What’s also important is that the “dynlibs” unit still needs to be integrated. Otherwise LoadLibrary() doesn’t work. Especially if you don’t use the LCL.