OpenGL Resource management
Met.3D uses a centralized OpenGL resource management system called MGLResourcesManager.
It is responsible for GPU resource lifetime management, resource
sharing across OpenGL contexts, actor registration, and OpenGL capability initialization.
OpenGL resources are typically managed manually through opaque resource handles. Without a centralized management system, this can easily lead to:
GPU memory leaks
Duplicated resources
Inconsistent ownership semantics
Unnecessary shader recompilation
For example, if multiple actors require the same shader or GPU buffer, each actor could otherwise create and manage its own copy independently.
MGLResourcesManager addresses these issues by storing graphics resources centrally and sharing them between consumers.
Managed resources are reference-counted and are only deleted once no component references them anymore and space is needed.
The manager additionally tracks the GPU memory usage of registered resources and uses this information to limit the total amount of cached GPU data.
Beyond GPU resource management, MGLResourcesManager also acts as the
central entry point for OpenGL initialization in Met.3D.
It validates OpenGL version compatibility, queries supported features
and extensions, and exposes capability information required by rendering
components.
The manager furthermore maintains the registration of actor factories and actor groups used throughout the system.
Design goals
The OpenGL resource management system was designed with the following goals:
Centralized GPU resource ownership
Resource sharing across rendering systems
Automatic lifetime management
Prevention of GPU memory leaks
Reduced shader recompilation overhead
GPU memory usage tracking
Resource caching and deferred eviction
Centralized OpenGL capability initialization
Centralized actor factory registration
OpenGL context management
MGLResourcesManager owns a dedicated OpenGL context that is used for
resource management operations when no other OpenGL context is currently
active.
This context is shared with all other OpenGL contexts used by Met.3D. As all rendering contexts in Met.3D participate in the same OpenGL sharing group, resources created through the resource manager are accessible from all shared contexts.
The dedicated resource manager context is primarily used for:
Resource creation outside active rendering passes
Background GPU resource initialization
Resource cleanup and deletion
Capability and extension queries during initialization
This design ensures that resource management operations can still be performed safely even if no rendering view currently owns the active OpenGL context.
Important
OpenGL resource creation and deletion always require a valid active OpenGL context.
The dedicated context owned by MGLResourcesManager guarantees that
the resource manager can perform these operations independently of
the currently active rendering view.
OpenGL initialization and capability management
MGLResourcesManager is responsible for initializing the OpenGL
runtime environment used by Met.3D.
This is done in MGLResourcesManager::initializeGL()
During initialization, the manager:
Verifies that the current OpenGL version is supported
Queries available OpenGL extensions
Detects supported rendering features
Checks implementation-specific limitations
Exposes capability information to rendering components
The queried capabilities are:
OpenGL version support
Available OpenGL extensions
Line width support
This functionality provides a centralized abstraction layer for OpenGL feature detection and prevents individual rendering components from having to perform redundant capability checks independently.
Actor factory and group management
MGLResourcesManager additionally maintains the registration of actor
factories and actor groups.
The registration of all available actors is performed in MApplicationConfigurationManager::registerActorFactories().
It registers the actor factories in the resource manager.
Actor factories are used to instantiate actors, while actor groups provide logical grouping and organization of available actor types inside the application. This is exposed to the user on actor creation, where the groups represent different categories of actors.
Centralizing actor registration inside the resource manager ensures that:
Actor factories are globally accessible
Actor categories remain consistent across the application
Text renderer management
MGLResourcesManager owns and initializes the global text manager used
throughout Met.3D. It is accessed through:
MGLResourcesManager::getTextManager()
The text manager uses the dedicated OpenGL context owned by
MGLResourcesManager for all OpenGL resource creation and management.
As the resource manager context participates in the global OpenGL sharing group, text rendering resources created by the text manager are accessible from all rendering contexts.
The text manager is initialized during the creation of the resource manager.
Managed resource types
All managed resources must derive from GL::MAbstractGPUDataItem.
The base class provides getGPUMemorySize_KiB() to get the size of the resource in memory,
and getRequestKey(), which identifies the item in the system.
Currently, the following OpenGL resources can be managed:
Textures (
GL::MTexture)Index Buffers (
GL::MIndexBuffer)Vertex Buffers (
GL::MVertexBufferorGL::MTypedVertexBuffer)Shader-storage-buffer objects (
GL::MShaderStorageBufferObject)Uniform block buffers (
GL::MUniformBufferObject)
Resource lifecycle
Resource creation and registration
You create GPU resources with a normal heap allocation. Newly created GPU resources must be registered with the resource manager using:
MGLResourcesManager::tryStoreGPUItem()
If successful, ownership of the resource is transferred to the resource manager.
The operation may fail if a resource with the same key is already registered in the system, or insufficient GPU memory is available. The caller is responsible for deleting the resource they tried to store.
To check whether a resource already exists, use:
MGLResourcesManager::contains()
Acquiring resource references
Once you successfully stored a resource, consumers must acquire a reference using:
MGLResourcesManager::getGPUItem()
This increments the internal reference counter of the resource.
Important
tryStoreGPUItem() does not automatically create an active reference for the caller.
Failing to call getGPUItem() after insertion leaves the resource with a reference count of zero.
Note
For textures specifically,
MGLResourcesManager::createTexture() wraps texture creation,
registration, and reference acquisition into a single call.
This helper function exists primarily to reduce boilerplate code.
Releasing resources
Once a consumer no longer requires a resource, it must release its reference using:
MGLResourcesManager::releaseGPUItem()
To release all currently held references at once, use:
MGLResourcesManager::releaseAllGPUItemReferences()
Resource caching and eviction
Resources whose reference count reaches zero are not immediately deleted. Instead, they remain cached inside the resource manager to allow future reuse without re-uploading data to the GPU.
Unused resources are only deleted when GPU memory pressure requires additional space.
The eviction order is determined by the order in which resources were released.
Shader management
Shader programs are managed separately from other GPU resources.
Instead of directly managing compiled shader programs, the resource manager stores shared instances of GL::MShaderEffect, which encapsulate shader loading and compilation.
Shader effects are created or retrieved using:
MGLResourcesManager::generateEffectProgram()
If the function creates a new shader effect instance, it returns true.
Existing shader effects are reused whenever possible.
Shader compilation itself is performed through the corresponding MShaderEffect::compile*() methods.
Shader effects are managed through shared ownership semantics and are automatically released once no component references them anymore.
Usage Guidelines
Always acquire references explicitly
After storing a resource successfully, always retrieve it again via getGPUItem() to establish ownership correctly.
Release resources when no longer needed
Failing to release resource references prevents the manager from reclaiming GPU memory.