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

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.

Mobile

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.

Testing

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.

Debugging

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

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 ?

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).

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.

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).

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!

I admit I don’t exactly agree with some of @Arioch points :slight_smile: though I agree with some others. To be clear, some of this is a discussion about “concepts” and judgment “what is more like X, what is less like X”. This is not mathematically precise to decide about. So the opinions below about “retained or not” are really just “from my point of view”.

My plans for future CGE though remain certain :slight_smile:

Both OpenGL and Vulkan allow to access GPU by giving you access to resources on GPU (like vertex data) and then to issue commands to render them. They are both immedate.

“Retained mode” is present in both OpenGL and Vulkan in some ways too. They both define some layers to wrap stuff you will send to GPU, not 100% of their objects “map” to some corresponding GPU data (at least not immediately, not directly).

And the “retained mode” is actually present in Vulkan in more important way: command buffers. In some sense, early OpenGL also had it with “display lists”, but these have been long deprecated and removed.

The command buffers in Vulkan are a big thing – allow to parallelize work you do on CPU, and then allow this work to be parallel more on GPU too.

Basically, both Vulkan and OpenGL feature a healthy dose of “retained” and “immediate”. If I would have to decide which one is more: Vulkan has more retained mode, due to command buffers.

To do this, we’ll create an abstraction layer, an “abstract renderer API”. That has then multiple implementations:

  • OpenGL (and friends OpenGLES, WebGL) – which will be just refactored existing renderer

  • Vulkan

  • and then we have the field open for more. I don’t plan at this point more (a new renderer is a big effort!) but it will be technically possible. If someone wants to e.g. develop Metal (macOS, macOS | Manual | Castle Game Engine ) or Direct3D renderer, it will be possible.

This is a proven approach that I saw in Ogre3D and Godot “from the inside” too. Looking from the outside, it’s no secret that e.g. Unity and Unreal have to approach it this way too, and probably all other engines with multiple renderers have something like this.

So at some point, it doesn’t really matter whether we can “match” concepts between OpenGL and Vulkan. (And some of them match nicely, like shaders, some of them completely don’t match, like command buffers.) But it doesn’t matter below some point – we’ll just have a different chunk of code doing OpenGL stuff, and different chunk doing Vulkan stuff. They all talk to “common chunk” which is CGE code that is agnostic about the renderer.

I agree with general sentiment that:

  • Vulkan is a lot of work. That’s why I plan to start in 2023, but I don’t even promise to have it production-ready in 2023.

  • The gains will not be life-changing for many game types. If you make “casual” games, in general if your graphics is not directed at modern realistic 3D graphics, then Vulkan will not drastically change what you can do with CGE.

    The differences start to appear only with more demanding graphics stuff, which is usually the 3D realistic stuff.

    E.g. our examples/platformer will just work the same, from user’s point of view, with Vulkan and OpenGL. But our examples/fps_game … you may see a speedup here.

Of additional note: Merely implementing Vulkan doesn’t solve all performance problems :slight_smile: And we have optimizations in CGE that could be more beneficial than OpenGL->Vulkan change, and are also easier to do – like X3D nodes memory optimization, or glTF playback using shaders. These optimizations will happen before Vulkan and will likely have an impact seen by more game types.

So Vulkan will come, but yes – it will be a big effort and yes, for some games it will not really matter. E.g. our “Unholy Society” ( https://unholy-society.com/ ) – will it benefit from Vulkan? Not really, it just doesn’t need Vulkan to be fast enough on all modern devices.

BTW I’m not alone in all of this :slight_smile: CGE is far from being a one-man effort anymore, Credits | Castle Game Engine .

1 Like

Seems to imply genre as a primary criterion… But i remember the first Mantle game was Civilization. Granted, their idea was not the responsiveness, but economy of resources.

The reasponing behinf Mantle and offsprings, at least in published articles, were said to be “closer to metal”, to make driver layers thinner and thinner (while mantaining secure multitasking).
While OpenGL and D3D 3-11 were gradually moving the same direction, they still were moving from old base, while M/V/DX12 were said to be designed ground up for this goal, shedding compatibility burden, etc. At least that was the marketing.

Some games would collect those benefits as lessened resources consumption, FPS games would also, probably, benefit from sliced “input lag”. However, this is exactly what platformer games would need, and they would need it even more than shooters!

Oh, and by the way, did you play “Identity V” game? The large part of the gameplay is running away from the threat, only having indirect clues (shadows and sounds) to guess the attack moment and jump sideway. To the effect that Bluetooth earphones totally loose it, ever, onlu wired ones can do it. I think i had yet to see a bona fide FPS that can not be played in BT headset :smiley:

…which maybe opens another can of worms (or road for glory, or both) for CGE: high-precision synchronization of sound and visuals :stuck_out_tongue:

True, the responsiveness is a general requirement regardless of game type. Platformer or FPS, you want the game to be responsive, and you may want to do cool graphic effects that put GPU to test.

I was specifically comparing 2 games examples/platformer vs examples/fps_game, not game types “platformer games” vs “FPS games”. Our examples/platformer just features a non-demanding graphics ( Platformer by Castle Game Engine ) while examples/fps_game (screenshot at the top of this thread, https://castle-engine.io/wp/wp-content/uploads/2023/04/fps_game.png ) is much more demanding. And it will be demanding more, we’re working on making it really impressive 3D graphics – thankfully I have real 3D graphic artists ( Concept art teaser: Huge graphical (and functional) upgrade to our FPS game is coming – Castle Game Engine ) to help with this :slight_smile:

Thank you all, for all the detailed information. You can learn a lot in CGE forums :face_with_monocle:

…thankfully I have real 3D graphic artists…

This is great. I need to say, that visual-appearance is always an eye-catcher. Also for choosing (using) a Game-Engine. F.e. if i see high quality games made with CGE i would be so impressed, that i would wish to create my games with CGE. Okay, nowadays i am bit older, i check more the technical aspects :wink:

Nevertheless, its a very good idea to get some artists on board, and make some fancy stuff with CGE. It will definetly catch attention, and it will also push the CGE to its limits or it will demand new tools (mat-editor, nodes, and so on…). This way the progress will be ongoing.

Later, the more users CGE gets, it will become a no-brainer in the area of more graphical games. imho.

1 Like