Compiling and running on different OpenGL versions

Started by
15 comments, last by ver_1_alpha 8 years, 3 months ago

Hello,

I'm trying to understand a basic principle on how OpenGL works when the compilation/linking is done with one version of OpenGL, but the program actually runs on a different version.

I understand that if the runtime version of OpenGL is greater than the one it was built in this is not a problem: OpenGL is backward compatible so the program will run on a machine where a newer version of OpenGL is installed.

My problem is the other way around. My program is heavily dependent on advanced shader technology. So I have function calls such as glUniform... throughout the code.

So let's assume I built my program on a machine with the latest version of OpenGL. Now I'm going to take it to a machine running an older version. Quite possibly, a function such as glUniform... is not even present there. Given that nobody distributes software with OpenGL - either DLLs on Windows or shared libraries on Linux - will my program simply crash if I run it on a machine with an older version of OpenGL?

I'm used to building applications that rely on other libraries - but their shared libraries are usually shipped along with the application. But I don't think OpenGL follows this practice: people usually have OpenGL on their machines and use their own version.

Can somebody explain to me how this works in the general case? For example, can I just query OpenGL at runtime for the version number and simply skip calls that rely on newer versions? Will the application even load properly?

Thanks.

Advertisement

Most of the openGL functions you use, are fetched from at runtime in the form of a function pointer (see openGL wiki on function loading).

Usually youd use a helper library like GLEW to automatically do the loading (it declares all the functions as function pointers and attempts to load them I assume).

So, presumably, if a function is not supported, the function pointer returned when trying to load a GL function at runtime will be nullptr or some other value (not sure what platforms wouldnt return nullptr) that will cause your program to crash if you try to call it...

This also means, you can always do checks at runtime to ensure you have the correct opengl version available, and even individual functions. If youre using a lower opengl version, you can try loading some functions not available in your gl version as an extension as well (like if theres something specific you need from the higher version, but you cant ask for full support of that version for some reason)

o3o

Hi Waterlimon,

Thanks! Very clear.

So, if I understand this correctly, I can build my application on, say, OpenGL 4.2. Then, at runtime, use glGetString (GL_VERSION), parse the string to determine the version, and avoid calling functions that probably won't be available.

For example,


#ifdef GL_VERSION_4_2
/* use 4.2 functionality here */
if(parsedversion(glGetString(GL_VERSION)) >= 42) {
   /* use the functionality here */
}
#endif

where "parsedversion" is some simple function that just parses the string with the version and generates an equivalent integer I can use for comparison purposes.

Of course, I could have a "} else {" statement for a fall back approach to the functionality in case 42 is not available on the running machine. But, at this point, all I want is to make sure it won't crash.

If everything is about call a function with a null pointer, then the above code should prevent the crash. Correct?

Thanks!

One more thing - although I'm not sure this is the place for the question:

I'm using GLEW on Windows, and include the GLEW DLL with the distribution.

Suppose I build with the latest version of GLEW then I try to run on a machine that is so old that the graphics card is unable to support the version I include in my distribution. Would glewInit() fail? Or - because the DLL is from the latest version of GLEW - could I see that glGetString returns a version I believe would work (because it is my GLEW DLL they are using), but the call could still fail?

In other words, I'm trying to protect myself from a crash. I have no problem reporting that a feature is not supported, but I cannot have the application crash. If glewInit() fails that's no problem because I will report this as an error.

Thanks again.

Something else to be aware of... you've said "advanced shader technology" and then you mention glUniform calls. glUniform is not advanced. In fact hardware that supports shaders has been around for longer than hardware that doesn't. It's perfectly reasonable to require this level of hardware as a bare minimum in 2015/2016, and not even worry about fallbacks.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Hi mhagain,

Thanks.

Unfortunately, what we distribute is a library that gets embedded into an end-user application that may go to thousands of end users. And I have no control over what end users are still using (you'd be surprised!).

So I have to assume the worst - even if that means people may still be at GL 1 (ok... maybe not that far back). But my source is full of #ifdef GL_VERSION_X_Y so that the end-user application can be compiled regardless of the version of GL they choose to use, and their end users can run it also regardless of what they have on their machine.

OpenGL versions can be kind of messy.

The easy way is to just check for a minimum OpenGL version at the start of your application and then just use everything that is available in that version.
The older the hardware is you want to support, the more work and/or limits you have.

There are Onboard and integrated GPUs that have lower OpenGL support. Lot of people are using Intel iGPUs on PC.
Then there are mobile devices and micro computers (Like the Raspberry Pi) that only support OpenGL ES.
Also mesa (oss Linux drivers) and Mac OS drivers only support higher OpenGL versions as Core version. (Core = no backwards compatibility)

You won't target most of that anyway, but I hope that gives a raw overview.

Extensions:

There are "Core Extensions" like ARB_direct_state_access (not to be confused with EXT_direct_state_access) that are always present starting with a specific version of OpenGL. In the case of ARB_direct_state_access it is Core since OpenGL 4.5 .

Core Extensions may also be supported when you have a lower OpenGL version. You just ask the driver if ARB_direct_state_access is supported and if yes, you can use the associated functions exactly the same.
Note that OpenGL may not list Core Extensions if you use a Version where the extension is garantied to be present.
E.g. if you use OpenGL 4.5 you may not find ARB_direct_state_access in the list of supported extensions.

If you go way back in time you find that many older ARB extensions (Before GL3.0 I think) still use ARB suffix in function and other names. Therefore they are never the same naming then the equal core version.

And then you have a lot of EXT or NV/ATI/AMD ect... extensions that are never guarantied to be present.
But some of them are basicly always avaiable. For example GL_EXT_texture_compression_s3tc.

Also the NV/ATI/AMD ... is only the name of the creator of the extension. You find nv extensions in AMD drivers and AMD extensiosn in nvidia drivers, etc...


The messy part is that you don't have to enable extensions.
So you may use functions of a extension withotu testing if the extension is supported.
As long as you run your application on hardware/drivers that support this extension, you will not notice this!

Osbios,

Messy all right...

Following the link that Waterlimon posted I learned that glGetString(GL_VERSION) is deprecated and has been removed in 3.1. So in order to find out the version I'm using at runtime I need to first know the version (!) so I know which function to call. I can certainly use #ifdef GL_VERSION_3_1 to decide which function to call depending on the compiler being used. But then I need to retrieve the runtime version to decide what to do.

For the moment we use no extensions, only the #ifdef GL_VERSION_X_Y at compile time, and glGetString(GL_VERSION) at runtime. I'm sure in the near future this will need to change...

Considering I created my own OpenGL header files from scratch after using the mess of GLEW I can understand why you have trouble with it. tongue.png

Does GLEW still have the glGetString bug? If I remember correctly that should have been fixed a long time ago.

So if you use glew, you just check the OpenGL version at runtime


//some init code to make the gl context



GLenum err = glewInit();

if (GLEW_OK != err) {

 //Problem: glewInit failed, blablabla...

 //And then we kill the application :'(

}



if (!GLEW_VERSION_3_3) {

  //terrible sad error here where we tell the customer he needs better hardware or drivers

  //And then we kill the application :'(

}



//if we reach this we are in happy OpenGL 3.3 land and can use everything OpenGL 3.3ish

not sure what platforms wouldnt return nullptr

Android, sadly.

Qualcomm's Adreno drivers always return a non-null function pointer, regardless of whether the function is actually supported.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement