https://github.com/godotengine/godot
For this contribution, I added Multisample Anti-Aliasing (MSAA) to the GLES2 backend of Godot. Aliasing is a property of rendered graphics where you see jagged lines caused by pixelation. Anti-aliasing comprises a range of techniques for reducing jagged edges in computer graphics. Below is a sample of different techniques from the QT documentation (open full size to really see the difference).
Almost all games have settings for anti-aliasing quality, typically FXAA, MXAA (at differing levels, 4X, 8X, 16X), and for higher end games TAA. Godot relies on MXAA which is usually built into the graphics drivers themselves. In the higher end backend (GLES3) this has always been supported but it has not been in the lower end (GLES2) backend.
GLES2 is the compatibility backend for Godot's renderer, it is meant to be leaner and able to run on almost any device.
A word about the backends here, Godot has two distinct rendering backends. GLES3 is its primary rendering backend, it supports the most features and has the better quality of the two. However, it is only supported by newer hardware (OpenGL ES 3.0 was released in 2012, so new here is relative). Many devices, especially lower-end mobile devices are still lagging behind and do not support OpenGL ES 3.0 and with it the better subset of features. Accordingly Godot offers a backend for older devices, GLES2. The GLES2 backend is new with the 3.1 release of Godot and still needs a little love and polish. One of the things many users missed was the ability to have Multisampled anti-aliasing.
At first I didn't think this would be such a large project. I have used MSAA in almost all of my OpenGL-based projects and it is usually easy to implement (famous last words, I know). In order to use MSAA in OpenGL ES 2.0, you need to check if the hardware supports it. Many hardware vendors provide support for features like MSAA, even though it isn't in the core specification of OpenGL ES 2.0. For Desktop applications (X11, WIndows, OSX) this can be done easily by polling the available extensions:
// Check for multisample support
config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample");
However, on Android and ios it wasn't so simple. If you read through the PR log you can see me struggling to understand how to do this simple operation in Android and ios. In the end, when the PR was merged, we were still unsure that it was done the best way possible. It works on all the hardware its been tested on. But the problem with supporting legacy devices is that oftentimes things are implemented in unexpected ways and things that should be easy end up breaking randomly.
In contrast to that nice single-line above. For android I needed to manually define the function pointers
#include <GLES2/gl2ext.h>
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT
And then resolve them to the library:
void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY);
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT");
glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT");
We think this will ensure maximum compatibility, but until someone tests on a really old device, we won't be sure.
In order to take advantage of MSAA, the renderbuffers used to render the screen need to be allocated with Multisample enabled. This is done with custom OpenGL function calls that were loaded above. This happens here.
Then, when rendering in order to draw the framebuffer to screen you need to copy it. The process of copying it is different whether you are using desktop, ios or Android. It can be found here.
Finally, with all that put together, you can now use MSAA in GLES2 but only on devices that support it. Devices that don't are still stuck with aliased rendering. Hopefully this will make it easier for people to produce high-end graphics on low-end software.
You can find the relevant PR here:
https://github.com/godotengine/godot/pull/28518
Fair warning, the PR contains days of desperately trying to get the changes to compile on Android and ios.
For fun I have included a bunch of bonus PR bug fixes of mine that have been merged in the last few weeks.
Before, all light is lost
Middle, solid color background taken into account, but leaking light
After, all light contained