I believe that the more modest approach of minimizing the OpenGL calls to rendering could provide a lot of benefits with minimal risk. This would allow the multithreading of operations that don't really need OpenGL access. The following are some basic examples, but I hope they demonstrate the types of changes I'm proposing.
- Getting access to an OpenGL surface (window, canvas, etc.) without waiting for the surface to be fully initialized would simplify embedding games within larger applications, applets, etc. Setting the background color is currently a standard part of game initialization. The following snippet is from BaseSimpleGame.initSystem():
display.getRenderer().setBackgroundColor(ColorRGBA.black.clone());
Looking at LWJGLRenderer, we see that this results in an immediate call to OpenGL:
GL11.glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a);
However, we could defer this update until the rendering phase without any negative impact to the system, just as long as we make sure that the value is pushed before a call to glClear().
2. Loading models in a background thread would be quite useful. If the OpenGL references within the Camera objects were minimized, then creating and manipulating the camera could be performed in any thread. Looking at the current Collada importer, this can be found:
Renderer r = DisplaySystem.getDisplaySystem().getRenderer();
int width = r.getWidth();
int height = r.getHeight();
// FIXME: THIS LINE IS SUPPOSED TO ONLY BE DONE IN A GL THREAD.
Camera c = r.createCamera(width, height);
This comment exists because the camera construction pushes frustum, view port, and frame changes to the OpenGL pipeline. If these changes could be safely deferred until rendering, then the FIXME comment above is no longer accurate.
3. Most of the states go through an initialization phase where they determine the types of extensions that are available. However, these values are not needed until the rendering phase. Picking BlendState as an example, the following code can be found as part of a onetime initialization within the constructor:
supportsConstantColor = supportsEq = GLContext.getCapabilities().GL_ARB_imaging;
supportsSeparateFunc = GLContext.getCapabilities().GL_EXT_blend_func_separate;
supportsSeparateEq = GLContext.getCapabilities().GL_EXT_blend_equation_separate;
supportsMinMax = GLContext.getCapabilities().GL_EXT_blend_minmax;
supportsSubtract = GLContext.getCapabilities().GL_EXT_blend_subtract;
These 5 values are only used within the codebase during the rendering phase. There are public accessors for these values, but they are either unused, or only used by callers active during rendering.
Some of the changes may have cascading effects, such as the interaction between ShaderObjectsState and several of the Pass objects. More analysis is needed, but I so far I'm not aware of anything that invalidates this concept.