Which Versions of OpenGL/ES Should You Target?
This post reflects my experience as of May 2014.
If you’re developing a cross-platform OpenGL application, or even targeting just a single platform, you will be stuck with trying to decide which among the many, many versions of OpenGL you should support. It’s a high-stake decision: the versions vary so much that it would be a nightmare workload to try to support them all.
It may be tempting to simply go with the latest and greatest: OpenGL 4.4 for desktop/console, OpenGL ES 3.0 on mobile. That’s great to support the cutting edge, but if it’s your only target, you will have a very restricted distribution. Both are not widely available right now, to say the least. Also, whatever advanced version you support, it’s important to also support at lease one fallback mode for older, “legacy” devices.
The question then is, what should be your “advanced” target version, and what should be considered a safe-yet-advanced fallback version that would let you run on the widest range of devices?
A general rule should be obvious: always use GLSL, and never use immediate mode rendering. Immediate mode is ancient and should be considered deprecated in all environments, even if you’re falling back to a version of OpenGL in which it was commonly used!
From my experience, I recommend this:
For OpenGL, target 3.3 (GLSL “#version 330”) and fall back to 1.2 (GLSL “#version 120”), and also make sure to check for extension support.
Forget about OpenGL 4.X: it’s still years away from being supported on mainstream devices. Right now, you’ll find it only on devices with dedicated gaming GPUs running the latest drivers. And actually, even OpenGL 3.3 is not ubiquitous. For example, many open source drivers on Linux are only now supporting all 3.3 features. For OS X, OpenGL 3.3 is the maximum version for many devices, even new ones.
So, really, 3.3 is about as cutting-edge as you can safely allow yourself to be right now while still supporting a wide-range of powerful devices. It’s not so bad: the API is from 2010 and has many advanced features.
Why should you fallback to version 1.2? Unfortunately, older versions of OpenGL did not require you to also support the matching GLSL version. On OS X, the situation is especially awful: OpenGL 3.2 is support on some devices, but the maximum supported GLSL version is 150. So why not fall back to OpenGL 1.5? Well, if you go back that far, actually there is little important difference between 1.5 and 1.2, and 1.2 is the minimum I have found on any device with OpenGL support, including emulated implementations (such as those using LLVM-pipe for shaders, or virtual machine 3D support). So if you support OpenGL 1.2, you will be able to run on pretty much all available devices in all environments.
For OpenGL ES, target 3.0 (GLSL “#version 300 es”) and fall back to 2.0 (GLSL “#version 100”).
Version 3.0 is great, but it’s only now starting to be available on newer phones and tablets. For years hence, most people won’t have more than 2.0.
Why not fall back to OpenGL ES 1.1? Well, any device that can do 1.1 can also do 2.0 in terms of hardware capability. The difference is in how up-to-date the drivers are. For example, all Apple mobile devices, even old ones, support 2.0 with the most up-to-date version of iOS they can run. Finally, OpenGL ES 1.1 is really so crude that it’s hard to imagine a cross-platform application that targets it. For those kinds of devices, you’d probably want to rewrite your whole application.
Check for OpenGL extensions! The core fallback profiles are quite minimal, but actually many important extensions are usually available even on devices that even only support the fallback, such as support for 2D textures arrays, multisampling, etc. Is it annoying to have to check for the availability of features in your code and have to fall back to an alternative when they’re not available? Yes, but that’s simply the reality of OpenGL programming. But if you do so, you’ll be able to use the platform’s hardware to the maximum.
And a quick note about the annoying versioning system for GLSL:
- OpenGL ES GLSL “300 es” is mostly equivalent to OpenGL GLSL “330”. This is great, because you’ll be able to share shader code between them.
- OpenGL ES GLSL “100” is mostly equivalent to OpenGL GLSL “110”.
So, the bottom line is that if you follow my advice here you will need, in essence, three versions of each shader. Luckily, the differences are usually just syntactical, and you might be able to get away with “#ifdef” if you prefer that route.
A crucial pain point, however, is support for 2D texture arrays: if the extension is not available, you can’t use the “texture2D” function in GLSL, and of course your whole method of loading and binding textures must be different. You’ll need an entirely different code path and approach to texture atlases.