OpenGL has been the leading 2D and 3D graphics API for many years. While it has generally evolved in a backwards-compatible fashion over the years, OpenGL 3.3 represented a significant departure by deprecating a large number of old API entry points. The API had grown quite large and complex, and there were frequently many ways of doing the same thing.
At the same time, adding support for – or even the ability to experiment with – many types of cutting-edge graphical techniques was oftentimes difficult. The reason lay in the competing needs to be a standard cross-platform API on the one hand, and a tool for advanced graphics R&D on the other. In order to ensure that OpenGL evolved in a controlled manner, proposed new features were put through a multi-step process that typically required more than a year for new features to be completely vetted and integrated into the standard. Not surprisingly, this became very frustrating to graphics researchers and those who wished to use the products of their efforts.
As one key strategy to address the frustrations of both slow, controlled evolution as well as better exploit the rapidly increasing power of sophisticated GPUs, significant architectural changes, modernization, and pruning of the CPU-side API was instigated along with the introduction of the GPU language GLSL to describe how key aspects of the rendering process were to be performed. As a result of these changes, OpenGL 3.3 became much more lean (the size of the API was cut nearly in half from that of OpenGL 2.1), less redundant, more easily mapped in an efficient manner to modern GPUs, and highly amenable to immediate adoption and use of specialized and experimental techniques. In so doing, graphics programming using the OpenGL API became a cooperative effort between CPU-side and GPU-side code. An important part of the design effort when writing OpenGL programs relates to decisions concerning what processing is best performed on the CPU versus what is best performed in GLSL on the GPU.
The OpenGL Shading Language (GLSL) was developed so that programmers could specify precisely how certain types of rendering operations previously shrouded inside the black box OpenGL graphics engine running on the GPU were to be performed. Using GLSL, graphics developers are now in control of many key aspects of the rendering process, and they can be made as elaborate – or as simple – as needed. GLSL was initially introduced in OpenGL 2.0, but its use was optional. OpenGL programs using only modern non-deprecated features now must use GLSL. Moreover, the GLSL language has evolved significantly since its first appearance in 2.0, and the collection of shader engine stages supported by GLSL has grown.
The only down side of all these changes is that simple things are somewhat harder to do than they were in OpenGL 2.1. But most serious users of OpenGL are less interested in how you do simple things than they are in the ability to do sophisticated graphics operations that were previously impossible, impractical, and/or too slow to support commonly required frame rates.
The latest released OpenGL specification at the time of this writing is 4.5. References to "shader-based OpenGL" typically indicate 3.3 and later versions that require GLSL code be written, at least for the two key graphics pipeline stages: vertex processing and fragment processing.
It is currently the case – and probably will be for the foreseeable future – that most OpenGL implementations continue to support the deprecated features of pre-3.3 OpenGL. This is due in large part to the fact that there is an enormous body of OpenGL code out there that would otherwise have to be rewritten or discarded. We will not study any of the deprecated features in this class, and you will not be allowed to use any of them in your projects.