Skip to content

Async Resource Loading

The ResourceManager decouples declaration from upload. Resources are first registered as CPU-side descriptors, then loaded asynchronously to the GPU on demand.

Loading Model

Descriptors

Every resource type has a corresponding descriptor that carries the CPU-side metadata needed to construct the GPU resource:

ResourceDescriptor
ShaderShaderDescriptor
Texture 2DTexture2DDescriptor
Texture 3DTexture3DDescriptor
ModelModelDescriptor
MaterialMaterialDescriptor
FontFontDescriptor

Descriptors are lightweight - they hold paths, formats, and flags, but allocate no GPU memory.

Registering Descriptors

cpp
auto res = ResourceManager::get();

res->register_shader(ShaderDescriptor::create("pbr", "shaders/vertex/pbr.axsl"_engine, "shaders/fragment/pbr.axsl"_engine));
res->register_texture(Texture2DDescriptor::create("albedo", "textures/albedo.png"_engine));
res->register_model(ModelDescriptor::create("cube", "models/cube.obj"_engine));

Triggering the Upload

Call load_from_descriptors with the target backend and the descriptor types to upload:

cpp
res->load_from_descriptors<ShaderDescriptor, Texture2DDescriptor, ModelDescriptor>(
    RendererBackend::OpenGL
);

Each selected descriptor type is uploaded concurrently. The call blocks until all uploads for the requested types complete.

Load State

Each resource slot tracks an async load state:

StateMeaning
PendingDescriptor registered, upload not yet started
LoadingUpload in progress on worker thread
ReadyGPU resource available for use
FailedUpload failed; resource is not usable

Passes and components that reference a resource by handle will receive a null/fallback resource if the load state is not Ready.

Generational Handles

ResourceManager uses a generational slot pool internally. Registering a resource returns a typed handle:

cpp
ResourceHandle<Texture2D> handle = res->register_texture(
    Texture2DDescriptor::create("albedo", "textures/albedo.png"_engine)
);

The generational counter in the handle prevents stale access after a resource is unloaded and its slot is reused.

Unloading

cpp
res->unload<Texture2D>(handle); // frees GPU memory, slot becomes available

WARNING

Unloading a resource that is still referenced by an active pass will not crash, but the pass will receive a null resource until a new one is loaded into the same slot.