5
$\begingroup$

I'm new to OpenGL, and I'm wondering what I need to pay attention to regarding versioning. The things I've been reading have been clear about there being version differences, and needing the appropriate OpenGL version for the functionality you're using. But they've mainly been talking about compiling and running programs on a single machine. For the most part they haven't explicitly dealt with complexities regarding compiling on one machine and running on another. (Specifically, what happens if the computer you're running on has an older version of OpenGL than the one you're compiling on.)

For example, take glDrawElementsInstanced. The Khronos page indicates this is available with OpenGL 3.1 and later. Obviously, if the headers for OpenGL on the machine I'm compiling for are version 3.0 or earlier, I'll get a compiler error. So on the machine I'm compiling on, I'll need to have OpenGL 3.1+ available.

However, I'm wondering what might happen if the machine I compile for has OpenGL 3.1+ available, but the machine I'm running on only has support for 3.0 or earlier? Will the program that uses glDrawElementsInstanced refuse to load? Will it run but crash once I call the glDrawElementsInstanced() function? Will it work fine because the actual implementation is compiled into my program, and it only uses common back-end functionality? Is the answer different for static versus dynamic linkage? -- And perhaps most importantly, if it wasn't glDrawElementsInstanced but some other function, is there a way I can determine this on my own?

I'm interested in distributing on Windows, Mac and Linux, so if there's any differences in behavior between the platforms in this regards, I'd be interested in knowing.

$\endgroup$
3
$\begingroup$

After running across an aside in a tutorial and doing some further digging, I think I understand this now.

According to the OpenGL ABI specification, only the functions defined in OpenGL 1.2 need to be present in the GL/gl.h header file. (At least for Linux - other platforms may be different. This answer indicates that Windows may expose only OpenGL 1.1 functions by default.) Functionality from more recent OpenGL versions (even commonly used functions) may not even be defined in the header files. -- This seems to be the case for glDrawElementsInstanced. In the headers of one Linux version I looked at, by default glDrawElementsInstanced isn't exposed by the the headers, even though OpenGL 4.5 is supported.

Instead, the functionality from newer OpenGL versions are apparently handled through the OpenGL extension system. (Even if it's not strictly an "extension", but part of standard functionality.) That is, each individual user is nominally responsible for loading the function address into the appropriate function variable using the appropriate (platform-specific) *GetProcAddress() function from the GL/glext.h header. The usage is to pass the appropriate string to the function, which will return a function pointer to the appropriate function (if present), or a null pointer if the functionality can't be found. (See the tutorial section for more detail on usage.)

This is, obviously, somewhat less than satisfactory if you're using modern OpenGL features. There is a preprocessor define GL_GLEXT_PROTOTYPES which, when defined prior to including GL/glext.h, will enable the definitions of a large number of standard functions. However, this may not work robustly if you're running on a computer which doesn't implement all of those functions which you're using. (You're likely to get missing symbol error during shared library loading.)

The better way to handle things is to use the OpenGL Extension Wrangler (GLEW). This hides the heavy lifting of the whole *GetProcAddress() process, defining symbols like glDrawElementsInstanced directly in the glew.h header. So long as you call glewInit() after initializing OpenGL but before using any version dependent function, these functions should be initialized appropriately if available, or to a null pointer if not.

You can either test for the function pointer being non-null, or use the GLEW-provided version test variables like GLEW_VERSION_3_1, which are booleans (not compile-time defines) indicating if that OpenGL version is supported on the computer the program is running on. Alternatively, you can test on a feature-by-feature level by using glewIsSupported()/glewGetExtension(). You can look up the respective strings for individual extensions at the OpenGL Registry. It doesn't lend itself to forward searching, but may permit use of features prior to the nominal version of OpenGL in use.

So why wasn't this clearer to me before? I think it's because most of the tutorials and documentation about OpenGL simply assume that you're using GLEW. Despite its name, GLEW isn't just about extensions, it also abstracts much of the version-to-version compatibility issues. As long as you put use behind version checks and don't actually attempt to call a non-supported function, GLEW hides all the pesky details about functions which aren't actually being implemented.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.