PDA

View Full Version : Easy usage of GL 3.1 / 3.2 extensions in C++



ijc12
10-26-2009, 08:30 AM
I recently wanted to use some of the newer functionality found in OpenGL 3.1 and 3.2. However since I was using glew and it only supports GL versions up to 3.0, I had to manually add and initialize unsupported functions myself. This can be quite a pain, so I decided to write some code to automate this process (and replace glew).

It works in two steps

In the first step all the gl and wgl functions found in "glext.h" and "wglext.h" are parsed and stored in two files called "glfunc_test.h" and "glfunc_test.cpp"

In the second step a small win32 project is compiled which includes both these files. The resulting program creates a OpenGL context and requests function pointers to every function in "glext.h" and "wglext.h". It spits out two files "opengl.h" and "opengl.cpp". "opengl.h" contains function pointer declarations for all the gl/wgl functions supported by your video driver and "opengl.cpp" contains the definitions and a function to initialize the function pointers.

After generating "opengl.cpp" and "opengl.h" they can be included in your own opengl projects to have easy access to the GL/WGL extensions supported by your video card.

I don't know how useful this is going to be to anyone, or if something like this already exists. It was useful to me so thats why I'm posting it here. If you have any questions you can put them in this thread.

The files can be found here:

http://rapidshare.com/files/298161299/gl_func.rar

or

http://www.megaupload.com/?d=ENJG8KRB

Ilian Dinev
10-26-2009, 09:19 AM
Good luck with that file requiring paid-access.

Here's the way:


// file gl_extensions.h
#ifndef OPENGL_MACRO
#define OPENGL_MACRO(proc,proctype) extern PFN##proctype##PROC proc
#define OPTIONAL_EXT(proc,proctype) extern PFN##proctype##PROC proc
#endif



OPENGL_MACRO(glCompressedTexImage2D,GLCOMPRESSEDTE XIMAGE2D);
OPENGL_MACRO(glGenerateMipmap,GLGENERATEMIPMAP);

OPENGL_MACRO(glGenBuffers,GLGENBUFFERS);
OPENGL_MACRO(glBindBuffer,GLBINDBUFFER);
OPENGL_MACRO(glBufferData,GLBUFFERDATA);
OPENGL_MACRO(glMapBuffer,GLMAPBUFFER);
OPENGL_MACRO(glUnmapBuffer,GLUNMAPBUFFER);
OPENGL_MACRO(glDeleteBuffers,GLDELETEBUFFERS);
OPENGL_MACRO(glGetBufferParameteriv,GLGETBUFFERPAR AMETERIV);
....
OPTIONAL_EXT(glRenderbufferStorageMultisampleCover ageNV,GLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENV);

(copy/paste, double-click, ctrl+shift+U to convert to uppercase)



// file engine_init.cpp

#define OPENGL_MACRO(proc,proctype) PFN##proctype##PROC proc
#define OPTIONAL_EXT(proc,proctype) PFN##proctype##PROC proc
#include "gl_extensions.h"

static PROC uglGetProcAddress(const char* pName,bool IsOptional){
PROC res = wglGetProcAddress(pName);
if(res || IsOptional)return res;
MessageBoxA(0,pName,"Missing OpenGL extension proc!",0);
ExitProcess(0);
}
static void InitGLExtentions(){
#define OPENGL_MACRO(proc,proctype) proc = (PFN##proctype##PROC)uglGetProcAddress(#proc,false )
#define OPTIONAL_EXT(proc,proctype) proc = (PFN##proctype##PROC)uglGetProcAddress(#proc,true)
#include "gl_extensions.h"

}




// file whatever.cpp or whatever.h
#include "gl_extensions.h"

...
glActiveTexture(...);


Of course, at places you need to include gl.h and glext.h beforehand.

Soo, you want to use a given ext-proc? Just paste its name in that header-file, together with its uppercase name. Done.

ijc12
10-26-2009, 09:25 AM
a) it doesn't require paid access, just click on free user.

b) The reason I made this is exactly because I don't want to manually add every extension I want to use, like your method requires

Ilian Dinev
10-26-2009, 09:26 AM
a) "This file can only be downloaded by becoming a Premium member

There are no more download slots available for free users right now. If you don't want to become a premium member, you might want to try again later."

Try MediaFire :)

b) there are around 114 useful extension-procs. It takes <5 minutes to "manually" (or via simple regexp) add them. It takes <3 seconds to add a new one when you need it :) . Plus, this reduces IntelliSense clutter.

Ilian Dinev
10-26-2009, 09:48 AM
Finally got a slot, and it's nice ;) . Does exactly what I meant by regexp. Lists all 1714 func, of which ~100 are strict GL3.x . And then, glfunc_test.cpp ouch :) . You know, you could've made that into a loop ^^. And removed the AddFunctionDec()/etc string clutter.

Here's a mirror host of that file: http://dl.getdropbox.com/u/1969613/openglForum/gl_func.rar

ijc12
10-26-2009, 04:55 PM
. And then, glfunc_test.cpp ouch :) . You know, you could've made that into a loop ^^. And removed the AddFunctionDec()/etc string clutter.


What do you mean?

LangFox
10-26-2009, 06:11 PM
Automation is always helpful. Thanks!
And you should parse gl3.h too.

James A.
10-27-2009, 05:55 AM
Hey, does any one know of there is something like this for strict GL 3.2? Is Ilian's method the best way just now? I guess 100 or so procs isn't so much.

ijc12: Is is ok to try and edit your code to parse gl3.h? :)

ijc12
10-27-2009, 06:13 AM
sure, you can post the results here if you like

I only looked briefly at gl3.h, I tried to compile my own (3.2 forward compatible) engine with it and it had several functions depreciated even though they shouldn't have been. So I don't think it's 100% correct yet.

James A.
10-27-2009, 06:17 AM
Cool, well I might not have time to do it until the weekend. But I'll definitely post it here if I get it done.

James A.
10-28-2009, 06:51 AM
I had a quick go at editing your code in glfunc to make it parse gl3.h it seems to work. there is no .exe in that zip so you need to compile it all yourself (boost is required)

i changed it so that the parsing parts go: for gl3.h

std::string gl3;
LoadTextFile("GL\\gl3.h", gl3);
IterateFunctions(gl3, GL3_H);

std::string wglext;
LoadTextFile("GL\\wglext.h", wglext);
IterateFunctions(wglext, WGLEXT_H);

std::string outPath = "glinit\\";
std::string fileName = "glfunc_test";

BuildHeader(outPath, fileName, GL3_H);
BuildCPP(outPath, fileName, GL3_H);
for glext.h

std::string glext;
LoadTextFile("GL\\glext.h", glext);
IterateFunctions(glext, GLEXT_H);

std::string wglext;
LoadTextFile("GL\\wglext.h", wglext);
IterateFunctions(wglext, WGLEXT_H);

std::string outPath = "glinit\\";
std::string fileName = "glfunc_test";

BuildHeader(outPath, fileName, GLEXT_H);
BuildCPP(outPath, fileName, GLEXT_H);

But glinit doesn't work when you parse for gl3.h because it's trying to get pointers to functions that are not extensions returnable from wglGetProcAddress (or maybe I am wrong? Any hints?). I'll try and fix that this weekend, but for now here is a half working version, if anyone wants to fix it for me :)

edit: I guess the functions it is not registering can be accessed anyway from the opengl32.lib as per normal, maybe :)

www.phasersonkill.com/dl/gl%20func.zip (http://www.phasersonkill.com/dl/gl%20func.zip)

ijc12
10-28-2009, 08:02 AM
I'm no DLL expert but when you use the windows native dll functions instead of wglGetProcAdress it does seem to return non-null function pointers

e.g:



HMODULE handle = GetModuleHandle(L"opengl32.dll");

glCullFace = (PFNGLCULLFACEPROC)GetProcAddress(handle, "glCullFace");
if(glCullFace) {
AddFunctionDec("PFNGLCULLFACEPROC glCullFace");
AddFunctionDef("PFNGLCULLFACEPROC glCullFace");
AddFunctionInit("PFNGLCULLFACEPROC","glCullFace");
}



So maybe that would work

James A.
10-28-2009, 04:15 PM
so you can't just use the non extension calls as you would from normal windows gl (is that gl 1.1?)

ijc12, you obvioulsy know more about DLLs than I do, your method worked, so I have changed your code to use a brute force method checking wglGetExtension first and then if it returns NULL checking GetProcAddress.

There is one problem with your regex, it has trouble around glGetString and so everything from glGetString to glViewport is defined incorrectly in the output code, that's only 9 functions though :) i fixed them by hand the and the new opengl.h/cpp seems to work on a simple example of mine.

here is the source again.
www.phasersonkill.com/dl/gl%20func.zip (http://www.phasersonkill.com/dl/gl%20func.zip)

ijc12
10-28-2009, 04:59 PM
Well this is the first time I've worked with explicit linking to a dll. Before I only used implicit linking with ".lib" files, or simple static linking to my own libraries. So the next part may contain some nonsense :)

I'm not sure why wglGetProcAddress doesn't return function pointers for some of those functions. As you said they are probably implicitly linked trough "opengl32.lib", and obtaining function pointers to them would probably cause conflicts with function prototypes defined in gl.h. But since gl3.h doesn't define any prototypes by default (?) you can't even use these functions with implicit linking when using gl3.h.

I think it would be better to just drop the implicit linking entirely and load the dll manually and initialize every function trough
the windows DLL functions instead of using wglGetProcAddress. I was working on that today, but I ran into some problems, because a few of the basic wgl functions to establish a context etc have prototypes in wingdi.h (expecting implicit linking), so I can't define a function pointer with the same name or I get a "trying to redefine function blabla" error :p. So yeah... I dunno. I guess the situation isn't ideal right now.

Ilian Dinev
10-28-2009, 05:05 PM
Fortunately, there's no reason to enforce runtime loading of those funcs via GetProcAddress() :) .

James A.
10-28-2009, 05:11 PM
what do you mean? which functions?

Ilian Dinev
10-28-2009, 07:33 PM
glCullFace and co.
Btw, I like the results in the "\output\" folder, where the .cpp loads only ~340 procs. Maybe so far I was only seeing some intermediate results, where for each dynamically loaded proc, a string gets concatenated.
*thumbs up*

James A.
10-28-2009, 09:08 PM
I tried not using GetProcAddress() for glCullface etc. and just including gl3.h in my project but it complained that glCullface wasn't defined. Admittedly I tried it only quickly before work this morning. Using GetProcAddress() with them and the same project worked fine.
Can you please explain in more detail.

James A.
11-01-2009, 10:52 PM
No hints Ilian? What's the best way of accessing this stuff with gl3.h

I finally got a GL3.2 and glsl 1.5 test app up and running using this, TBH i didn't really have to change much aside from the shader source, i can't comment on it's completeness.

ijc12
11-02-2009, 08:05 AM
I modified the program a little bit, the intermediate step wasn't really necessary so I removed that. I also modified some of the regexps because of the error James mentioned.

There are now 2 executables, "glinit_gl3.exe" to generate a gl 3.2 forward compatible interface based on gl3.h

And "glinit_glext.exe" to generate a gl 3.2 compatibility profile interface based on the latest version of glext.h

http://www.megaupload.com/?d=FSUMSPHG

Ilian Dinev
11-02-2009, 08:41 AM
No hints Ilian? What's the best way of accessing this stuff with gl3.h
Neither method (static-linking .lib vs win32 getprocaddress) is better. Well, static linking is a wee bit faster, not that it matters:
"call xxxPatchedAddress" // some older compilers make this a jmp+call, though.
vs
"call dword ptr [xxxDynLoadedAddr]"


So, just do these things the way you like :)

James A.
11-02-2009, 09:23 AM
I modified the program a little bit, the intermediate step wasn't really necessary so I removed that. I also modified some of the regexps because of the error James mentioned.

There are now 2 executables, "glinit_gl3.exe" to generate a gl 3.2 forward compatible interface based on gl3.h

And "glinit_glext.exe" to generate a gl 3.2 compatibility profile interface based on the latest version of glext.h

http://www.megaupload.com/?d=FSUMSPHG

hey ijc12, that's great. Do you mind if i host it on my website? it's probably quite useful for others as well.

ijc12
11-02-2009, 09:28 AM
I don't mind.

Although it should probably contain a readme file with a little explanation or something. Or you could just add a readme.txt with a link to this thread.

yooyo
11-02-2009, 01:57 PM
@ijc12:
Is it correct to use GetProcAddress instead of wglGetProcAddress. I read somewhere that depending on pixelformat, active rendering context can return different entry points when you use wglGetProcAddress.

Long time ago I made similar tool (parse glext.h and wglext.h) and generate cpp file (glExtMap.h & glExtMap.cpp). Generated code is almost the same as yours except I added flags structure for checking extensions (collect all known extensions and add flag in big bit-field structure).

But.. I lost parser source code and all I have is parser executable :) Today, Im too lazy to write new parser, so I'll use your work. Thank you very much.

Ilian Dinev
11-02-2009, 03:31 PM
GetProcAddress returns null for funcs the opengl32.dll doesn't export. (use Dependency Walker to see the list of exports) . It is not hooked, as the set-in-stone static linking easily renders that useless. Instead, the exported funcs are hooked by design, (note: the funcs' addresses stay the same). For example, in opengl32.dll, this is glBindTexture():
mov eax,dword ptr fs:[00000018h]
jmp dword ptr [eax+0A08h]



wglGetProcAddress is also hooked in a similar way by the video-driver and returns context-dependent func-addresses. For funcs that are not already on the static-lib's exports-list.

James A.
11-02-2009, 06:52 PM
ijc12, you want to write a README and i'll add it to the zip you linked to?

ijc12
11-03-2009, 05:28 AM
Is it correct to use GetProcAddress instead of wglGetProcAddress. I read somewhere that depending on pixelformat, active rendering context can return different entry points when you use wglGetProcAddress.

I don't know if it's strictly correct but it's the only way to get function pointers to certain functions since wglGetProcAddress won't return them. In any case GetProcAddress is only used for gl3 and only when wglGetProcAddress fails. Maybe using function prototypes instead of function pointers would be more correct for these implicitly linked functions, I don't know.

@James

I added a little readme file, you can put this version on your page

http://www.megaupload.com/?d=6XBRFUN7

James A.
11-08-2009, 03:30 AM
Sorry for the late reply,

I uploaded the latest version from ijc12 here:
http://www.phasersonkill.com/dl/gl%20init.rar