GLES2.0 everywhere (thanks to LWJGL3)

LWJGL has gone from strength to strength since being reborn from v2 – the differences are subtle from the API point of view but make for a library that’s much more robust and future proof (if such a thing is possible) and certainly as you’ll see far more flexible.

One fairly recent development is the inclusion of GLES2.0 while some people fail to see the importance of targeting GLES2.0 they also seem to forget its well and truly embedded in every single browser on the desktop and its not just a graphics library for phones, in fact its pretty well everywhere…

The opportunity to lift shaders and code from a much wider range of platforms and with almost no or very minimal porting and just have it work is altogether just too nice a prospect to ignore!  The real gem though is the ability to develop on an embedded system like for example an Open Pandora, where GLES is the only flavour GL available and then take that “binary” and have it work on such a different platform as windows (without need of recompiling).  Something that really is a “universal binary!”

Before going further I must say a big thanks to Loannis Tsakpinis, who aside from lightning a fast response on the bug tracker, gave generously of his time to help my fumbling towards a solution on the LWJGL forum – without his help the rather sneaky solution to running on the windows platform would never have happened.

The main issue is unlike Linux where you can just install a package that provides libEGL and/or libGLESv2 things are somewhat different on windows, my initial knee jerk reaction was why don’t they just bundle ANGLE.  However this could cause problems where other SDK’s are installed or even where the graphics board vendor actually does bother to provide GLES rather than just OpenGL.  In short forcing ANGLE as a solution could be problematic and would reduce flexibility.

It dawned on me that GLESv2 is a subset of OpenGL 2, what’s more though, OpenGL 2 does actually seem to be a working super set of GLESv2, i.e. you can make a working application with OpenGL 2 but using only GLESv2 calls.

This lead me to see if I could get a LWJGL GLESv2 application to work on windows but dynamically linking to opengl32.dll at run time.

Bear with me! it will all become clear as we look through a code example…

First of all there is a mixture of normal and static imports, the only imports that we are compiling against are the GLES ones and not OpenGL.  The reason for static imports is that it allows external classes to be used without qualification

so

GLES20.glClearColor(0,0,0,1);

becomes

glClearColor(0,0,0,1);

Not only does this save typing and aids readability but it also means you can lift C code fragments and drop them straight into your Java boiler plate and odds on they just work! anything that aids and speed learning and experimentation is welcome indeed…

The first bit of windows specific code is just before GLFW is initialised

if ( LWJGLUtil.getPlatform() == Platform.WINDOWS ) {
    // pretend we're using GLES in windows, instead use a subset of OpenGL 2.0 as GLES 2.0
    Configuration.LIBRARY_NAME_OPENGLES.set("OpenGL32");
    Configuration.EXPLICIT_INIT_OPENGLES.set(true);
    org.lwjgl.opengles.GLES.create(org.lwjgl.opengl.GL.getFunctionProvider()); // omg?!
}

fortunately there is only one other (even smaller) stanza of platform specific code and what is going on is fairly straight forward.  When LWJGL’s GLES20 class “starts up” its actually loading the OpenGL32.dll and linking native functions like for example glClearColor to the OpenGL version.  This works as not only is the functionality identical but so is the ABI (Application Binary Interface) all this means is the function name and parameters are all identical.

Although I didn’t need to qualify the create method I’ve fully qualified it to avoid any possible confusion down the line, however the clever bit (not mine) is using the GL function provider to dynamically link the native library (normally it would need to use EGL’s eglGetProcAddress, as a cross-platform alternative to wglGetProcAddress or glXGetProcAddress.)

Having linked to OpenGL instead of GLES, we need to make the correct type of “surface” for OpenGL or GLES to actually draw on.

if ( LWJGLUtil.getPlatform() == Platform.WINDOWS ) {
    glfwWindowHint (GLFW_CLIENT_API, GLFW_OPENGL_API);
} else {
    glfwWindowHint (GLFW_CLIENT_API, GLFW_OPENGL_ES_API);  
}

simples! no really, honest!

Literally everything else is “as normal” for a GLESv2 application, obviously you must still test your end product on multiple examples of specific platforms, because different OpenGL and GLES vendors can some times have subtle or even not so subtle differences.  Not all implementations of a standard are equal!

here’s some code for you to play with LWJGL-GLES.tar.gz

Enjoy!

 

footnote MacOS X

There is a fair chance that with a bit of tweaking of the if conditions and the right library name this could be made to work on a Mac as well – however I don’t have access to a Mac.  If someone with a Mac does want to volunteer just leave your email address in the comments section and I promise not to publish the comment!

Leave a Reply

Your email address will not be published. Required fields are marked *