![]() |
![]() |
![]() |
![]() |
There are two types of state in Gthree, regular data, and GL resources.
Regular data is things like the object in the scene, their positions and relations, but also host side geometry data like the vertex position and colors as well as the pixbuf data for textures. Another form is GLSL code (in textual form).
GL resources are something that are tied to the OpenGL context, and any time such contents is manipulated or referenced the GL context must be active. GL resources are of several types: buffers (i.e. geometry data), textures, programs.
This is particularly sensitive when it comes to destroying state, such as when finalizing a widget, or even more so when moving between different GL contexts (such as when a widget moves to a new toplevel window). The main problem here is that finalization can be arbitrary delayed by a reference being held somewhere, and by the time we're finalizing we may no longer have access to the GL context.
GL resources are transient and generated from regular data when needed. As such it can be destroyed and recreated as needed. This is called realization/unrealization. For example, to realize a texture means allocating a gl texture id for it and uploading the data, and unrealizing it means freeing the data and deleting the id.
The toplevel owner of data is the #GThreeArea widget. It owns the scene, as well as as camera object (which is typically also part of the scenen. It also has a renderer object, but only while the widget is realized. A more complex program might have multiple scenes and/or cameras, but only one renderer per GL context, because the renderer keeps track of the GL state and would be confused if something else re-used the context.
The scene contains both regular data and GL state. For example, it indirectly references vertex arrays and textures, which are created and uploaded to the GPU on when needed. This means a scene can only be used by one GL context at a time. However, by unrealizing and then re-realizing the resources it can be switched to a different context.
The fact that some object store both regular data and GPU resources makes it lifetime management somewhat complicated. Take for example a scene. You can dynamically add objects to a scene either before or after it is displayed without problem, because this just adds regular data. The data can then be realized as needed during rendering, when we're guaranteed to have an active GL context. However, if you remove an object (to free it or add it back later), or move it to another scene, then there is no guarantee that the the corresponding GL context is active, so you can't directly unrealize it.
All objects that may hold GL resources are of the type GthreeResource[1], and are realized for one single GL Context at a time (or are unrealized and independent). You can call gthree_resources_unrealize_all_for() to unrealize all the resources for a Context, but this is typically done automatically when unrealizing the GthreeArea widget that owns the Context.
The only points we can guarantee that the GL context is active is during rendering, widget realization and widget unrealization. This means all unrealization must be postponed until one of these points. For finalization at odd times (i.e. when the context is not active) this means it frees all the regular data, but keeps the GPU data around in an queue which is freed at the next oportune moment. Every time you render this queue is flushed, but you can also trigger it manually i needed by calling gthree_resources_unrealize_all_for().
It is sometimes hard to track what resources are in use, and which you may want to allocate, but gthree has some simple mark-and-sweep system that lets you find it. You call gthree_resources_set_all_unused_for() on a context, then iterate over all important resources, calling gthree_resource_set_used (). Then you can call gthree_resources_unrealize_unused_for() to unrealize all resources that are still realize but not actually in use.
[1] Actually programs are not, but all programs are owned by the renderer which is tied to realization of the widget.