Big rendering refactor: fully modern OpenGL support (3.3 core profile), mobile OpenGLES more functional (3D textures, occlusion query, more OpenGLES 3 features), ancient OpenGL better (reliable fallback to even 1.1 rendering in VMs), modernized GLSL code

Posted on

fps_game demo
Run parameters submenu
OpenGL information

We have made a few significant refactors of our low-level OpenGL(ES) code, to support better both modern GPUs, ancient GPUs and mobile GPUs. Everybody wins! 🙂

Modern GPUs

We have now much better support of new OpenGL features. If we have shaders, we know we have shaders from “core”, and we initialize them with the same code everywhere. Same for FBO (Framebuffer Object). Most new GPUs support now OpenGL 4.x. So for many things, we can just assume that modern OpenGL will have them in “core”.

So we have implemented a code path using 100% “core profile” OpenGL 3.3 context (using deprecated stuff is prohibited). To force using it, set TGLFeatures.RequestCapabilities to rcForceModern. Or pass command-line option --capabilities=force-modern . Or in CGE editor click “Run -> Run Parameters -> Force Modern Rendering Context (–capabilities=force-modern)”.

Our upgraded renderer:

  • Automatically converts quads to triangles as modern OpenGL(ES) API don’t support quads.

  • Uses image formats without luminance, instead we use texture swizzle.

  • Creates and uses Vertex Array Buffer.

  • Queries OpenGL(ES) extensions in new way

  • Uses shadow samplers following OpenGL(ES) core

The default is a smart choice. We create a “compatibility” context, and

  • if it has a new OpenGL version — we will actually use only the new API , just like from “core” profile. As mentioned above, OpenGL >= 2 implies a lot of things (VBO, shaders) and we will use them. Later versions also imply some nice things, e.g. OpenGL >= 3 implies FBO.

  • However, if the provided OpenGL version will be low (< 2), we will automatically set GLFeatures.EnableFixedFunction to true, and follow ancient fixed-function rendering path.

This makes the approach “automatic”, and it is indicated by (default) TGLFeatures.RequestCapabilities value of rcAutomatic.

Our treatment of old GPUs is now simpler

If you don’t have OpenGL 2, then we assume you also don’t have a lot of other things (we will not even try to use them through old extensions). Without OpenGL 2, we assume you never have shaders or even VBO. To be precise, GLFeatures.Shaders is now always a simple negation of GLFeatures.EnableFixedFunction, same for GLFeatures.VertexObjectBuffer.

This makes things actually better for these ancient GPUs: it means that their support is more reliable. It is easier to write and test one simple “ancient fixed-function” code path when it doesn’t have so many variations. And you can test it easily: just set TGLFeatures.RequestCapabilities to rcForceFixedFunction from code. Or pass command-line option --capabilities=force-fixed-function . Or in CGE editor click “Run -> Run Parameters -> Force Ancient Rendering Context (–capabilities=force-fixed-function)”, then run as usual (F9 or click the button).

Rendering on such old systems supports unlit or Phong lighting. Some modern rendering features are not available (like PBR or shadow maps), but simple games will manage.

The renderer was really tested with actual OpenGL 1.1 implementation available on some Windows 2016 servers 🙂

Switching between modern and ancient OpenGL

We have a new command-line option --capabilities=automatic (or
--capabilities=force-fixed-function or --capabilities=force-modern). It is available in all CGE applications (TCastleApplication.ParseStandardParameters handles it, and it is called from CastleAutoGenerated unit).

We also have a new menu items in CGE editor to easily set it “Run -> Run Parameters -> …”.

view3dscene and the CGE editor itself also support these options. So you can test how does editor behave on ancient OpenGL implementations, just run it like this: castle-editor --capabilities=force-fixed-function.


Finally, the end result is also good for OpenGLES (usually on mobile, though it also works on desktop if you want). It is more consistent now with desktop OpenGL, bringing many rendering improvements to OpenGLES and simplifying the code in the process too. E.g. shadow maps now just depend on OpenGL ES 3, and use almost the same code as on desktop OpenGL, with shadow samplers in GLSL.

I wrote more about mobile improvements in this post.


I have also added a test application examples/research_special_rendering_methods/test_rendering_opengl_capabilities/. It exercises all rendering methods:

I have also extended default OpenGL 1-line report to contain vendor name and “modern rendering” (not GLFeatures.EnableFixedFunction), since they are important information about your GPU. It looks like this now:

Rendering Initialized: OpenGL 4.6 (Nvidia) (modern rendering: True) (for more info: LogGLInformationVerbose:=true)

The verbose report (the one you see if you enable LogGLInformationVerbose, you also can see it in CGE editor, use “Help -> System Information”) is also improved in many ways — more relevant stuff reported, better order.

Also our GLSL usage in now more modern

We advise you to not declare any #version in your GLSL code, and internally we will add a modern #version and also define a few macros that turn lowest-supported GLSL versions into modern versions. See CastleGLShaders unit for more comments.

We also automatically define precision for OpenGLES fragment shader, if you didn’t do it automatically.


You can use OpengGL debug context feature. Just set TGLFeatures.Debug.

Notable Replies

  1. Really nice progress !

    But the good old openGL 1.0 (webGL 1.0) will remain as a fallback solution. As i understand this. I mean, i would like to have such options, if i target some older devices / web-browsers.

    Maybe is get it wrong…I thought openGL 4.x or its development is not relevant anymore, because of vulcan. So my thinking was, that openGL developent ends with openGL vers. 3.xx. But i am wrong, or ?

  2. Note: OpenGL 1.0 and WebGL 1.0 are not related versions.

    WebGL 1.0 is a bit like OpenGLES 2.0 which is a bit like OpenGL 3.0… but these comparisons are not exact. In general, OpenGL and WebGL (and OpenGLES) are just different APIs (albeit very similar! but not exactly equivalent if you look at details) and their versions mean different things. The number “1.0” indicates very different capabilities (and age) when talking about OpenGL and for WebGL.

    As for our support:

    • Our web target will support WebGL 1.0 (optionally using WebGL 2.0 features is present), as per Web target – progress and plans – Castle Game Engine .

    • On desktops, we support as low as ancient OpenGL 1.1. We probably support even OpenGL 1.0, but I didn’t have any machine with OpenGL 1.0 to actually test so I cannot claim it. I very doubt you have any device with OpenGL 1.0. Even ancient virtual machines or servers without any sensible GPU will have OpenGL 1.1.

    We are indeed committed to supporting older devices, as the above post implies – Big rendering refactor: fully modern OpenGL support (3.3 core profile), mobile OpenGLES more functional (3D textures, occlusion query, more OpenGLES 3 features), ancient OpenGL better (reliable fallback to even 1.1 rendering in VMs), modernized GLSL code – Castle Game Engine , “everyone wins” in the sense that we improved both support for modern OpenGL and for ancient OpenGL :slight_smile:

    OpenGL is relevant, in short. It is right now the only graphic API that is truly cross-platform, available on all systems (old and new, desktops or mobile or web or Switch) one way or another, in my experience. (And in this paragraph I actually think about all the “OpenGL and similar APIs” , so “OpenGL, OpenGLES, WebGL”. Together they really cover everything.) I mentioned this in GIC 2022 slides too, Castle Game Engine - GIC 2022 - Google Slides .

    Maybe this will change in 10-20 years when Vulkan will get everywhere. For now, OpenGL is relevant and I’m certain it was (and is) a good decision to use it as our main renderer for CGE.

    That said, if you’re interested about Vulkan, note that I’m too :slight_smile: Exploring Vulkan renderer is on our roadmap, Roadmap | Manual | Castle Game Engine . I want to start it in 2023 (though I doubt Vulkan renderer will reach “production use”, i.e. be as good as current OpenGL(ES) render, in 2023; but it will be a start).

  3. Hey.

    Thank you, for all the details. Very interesting.
    So i dont need to worry. Vulkan is in the beginning and maybe the standards will change in round about 20 years.

    Is there any big difference between Vulkan and openGL 4.xx ? (Also DX 9.0 / 12 compared to openGL 4.xx).
    Just for interest. I would prefer openGL / vulkan instead of DX.

  4. There’s a big difference between Vulkan and OpenGL 4.x.

    While they are both modern, they expose very different API. Vulkan is much more low-level, has command buffers, allows for more parallelism. You can have better performance with Vulkan (and you can spread the work on CPU cores much better), but there’s a big cost in implementing it – application code needs to do a lot of work (and optimization) to actually leverage the possible gains offered by Vulkan. I imagine that “naive” Vulkan implementation wouldn’t gain anything over OpenGL implementation, in fact could be worse – but noone in practice can do “naive Vulkan implementation”, from what I hear in other engines (Godot) – once you jump into Vulkan it’s a lot of work. It pays off but after quite a lot of new effort.

    See e.g. Vulkan - Wikipedia for overview of Vulkan.

    I like this video: The Vulkan Graphics API - what it means for Linux - YouTube . My favourite quite: “once you can render a single triangle using Vulkan, doing the rest of the application is just a matter of typing” :slight_smile: (Not an exact quote, I watched it long time ago, just repeating from memory.)

    Vulkan also uses precompiled shaders in SPIR-V. The SPIR-V is actually also present in OpenGL 4.6 ( Standard Portable Intermediate Representation - Wikipedia ), so this bit is actually similar between Vulkan and OpenGL 4.

    As for DirectX (more specifically Direct3D, which is a rendering API and can be compared to OpenGL or Vulkan): essentially Vulkan is a bit like Direct3D 12. In contrast, earlier Direct3D is like OpenGL.

    We don’t plan Direct3D renderer backend at this moment. I speculated about it in the past, but practically there’s no need for it: OpenGL works great on Windows, old and new, and it doesn’t seem to change. And of course we’re reluctant to do a work a renderer that would be specific to 1 platform (Direct3D work would only benefit Windows, while OpenGL work benefits all platforms; Vulkan is also cross-platform, although not available everywhere yet).

  5. For what i understand, Vulkan (and also DX12 and Mantle) are the continuous flight from “retained mode”

    Basically, all those objects you would today create in CGE terms, looong times ago you would create in videodriver terms. Which could have been much simpler but set “one size fits all” constraint.

    While CAD applications were the main driver of development it worked well enough. But videogames craved for “microsecond responsiveness and sub-pixel rendering” and as they took the lead - the priorities changed to “deconstruct” videodrivers and to put more and more of it into userland, into “libraries” inside “application”. Which necessarily would make coding much more complex, as things given for granted (but in that “one size fits all” way) would have to be reimplemented and custom-tailored to every specific game.

    …and here is the question, do you really want to go THAT far as to kind of reimplementing the whole rendering pipeline? Michalis seems to be one of those maniacs. Are you, are your games? Not sure.

    For me, frankly, it is of near zero interest. To my needs GL FFP and retained mode would be enough. But CGE is a pack promising all-in-one: sounds, translucent graphic, cross-platforms, scripting and collisions. Probably i would’ve been able to pick those tools one-by-one to sorta kinda what i mighta need and glue them together, but… it won’t be worth the effort for long, perhaps forever.

    Would one day CGE go Vulkan i would be rather puzzled. To keep OpenGL 1.1 and Vulkan in one library, with their often antogonistic concepts and tradeoffs… And then, on top of it, making games that would actually make difference in their interactivity Vulkan vs GL (i feel for now michalis is making games that are close to “casual” ones). If one man would really manage to pull all this off single-handedly it would be an unprecedented effort!

Continue the discussion at Castle Game Engine Forum

4 more replies


Avatar for Arioch Avatar for michalis Avatar for sledge