in Engine

Castle Game Engine: 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

From Castle Game Engine: link to original post

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.