Resources

Purpose

Resources converts owned CPU descriptions into backend images, geometry, programs, pipelines and materials. Retained handles let assets and completed frames share immutable generations while the backend controls native retirement. A native resource domain is the live backend/context lifetime that owns those resources. A handle from that domain does not become usable in an unrelated context merely because both contexts use the same graphics API.

Interface

Types below are in CE::Rendering unless another namespace is shown.

Types and operations

API and purpose

Resources::Provider
Create images/font atlases, upload geometry and link programs on the selected backend owner. Immutable publication; adapter capabilities.

GraphicsDomain, GraphicsDomainStateChanged
Retain native lifetime observations without retaining native resources; distinguish initialization, shutdown and abandonment. Graphics domains.

CE::Assets::Images::Decoded
Own top-to-bottom CPU RGBA pixels returned by Images::decode(path/bytes), shared with toolkit loading. CPU preparation and upload; decoded image declarations.

Resources::Image, Geometry::Buffer2D
Retain immutable uploaded image/geometry generations. Native retirement.

Resources::Program, Resources::Pipeline, Resources::Material
Retain executable programs, validated fixed state and material recipes. Pipelines and materials.

Sampling::Sampler, CE::Assets::Shaders::Builder
Use optional immutable sampling and shader/material recipe capabilities. Sampling; shader recipes.

Sampling and shader choices

Type

Choices and details

Sampling::Options, Sampling::Filter

Independent minification/magnification with Nearest or Linear filtering. Immutable sampling.

Sampling::MipmapFilter, Sampling::Wrap

Mipmap None/Nearest/Linear; UV ClampToEdge/Repeat/MirroredRepeat. Sampling and UV behavior.

Sampling::Anisotropy

Disabled or MaximumSupported; an unsupported maximum resolves to isotropic filtering. Effective sampling.

CE::Assets::Shaders::Stage, ShaderStage

Indexed recipes support Vertex/Fragment; the separate legacy enum classifies shader files and includes additional stages. Shader definitions; legacy stage declarations.

Usage

Most applications receive retained resources through asset, text or UI loading. Call the provider directly when creating content outside those loaders. Both routes create immutable handles in the same selected graphics domain.

        ---
config:
  theme: base
  themeVariables:
    fontFamily: system-ui, sans-serif
    fontSize: 14px
  flowchart:
    htmlLabels: true
    curve: linear
    nodeSpacing: 22
    rankSpacing: 38
    padding: 12
---
flowchart TB
    accTitle: Resources · application uploads and retained draws
    accDescr: Local names omit Rendering::Resources::; ambiguous nested namespaces remain qualified. Arrows point toward the API or type used, not call order or data flow. Methods beneath type names are selected application entry points; Implement hooks marks engine-invoked overrides. Dashed arrows mark optional choices.
    k0(["Application<br/>loading work"]):::app
    k1("Assets::Images::decode(file): Assets::Images::Decoded"):::neighbor
    k2["Assets::Images::<br/>Decoded"]:::focal
    k3(["Application<br/>init_platform()"]):::app
    k4["<b>Runtime::<br/>Context</b><br/><br/>resources(): Provider"]:::neighbor
    k5["<b>Provider</b><br/><br/>create_image(Assets::Images::Decoded): Image<br/><br/>upload_geometry(<br/>Rendering::Geometry::Vertex2D[],<br/>Rendering::Geometry::Topology):<br/>Rendering::Geometry::Buffer2D<br/><br/>graphics_domain(): Rendering::GraphicsDomain"]:::focal
    k6(["Application<br/>platform-owner work"]):::app
    k7["Image"]:::focal
    k8["Rendering::Geometry::<br/>Buffer2D"]:::focal
    k9["Material"]:::focal
    k10["Pipeline"]:::focal
    k11(["Application<br/>prepare_render_frame()"]):::app
    k12["Rendering::<br/>DrawPacket2D"]:::neighbor
    k13(["Application<br/>report"]):::app
    k14["<b>Rendering::<br/>GraphicsDomain</b><br/><br/>snapshot(): Rendering::GraphicsDomainSnapshot"]:::focal
    k0 --> k1
    k1 --> k2
    k3 --> k4
    k4 --> k5
    k6 --> k5
    k5 --> k2
    k5 --> k7
    k5 --> k8
    k9 --> k10
    k11 --> k12
    k12 --> k9
    k12 --> k8
    k13 --> k14
    k5 --> k14
    classDef focal fill:#e7f3ef,stroke:#387d6b,color:#153d33,stroke-width:1.2px
    classDef neighbor fill:#f0f3f8,stroke:#8c9bb1,color:#35445b,stroke-width:1px
    classDef app fill:#fff2df,stroke:#c09452,color:#674515,stroke-dasharray:5 3
    classDef system fill:#eaf0fc,stroke:#617fab,color:#263f69,stroke-width:1.2px
    linkStyle default stroke:#7e8fa7,stroke-width:1.2px

    

Local names omit Rendering::Resources:: where unambiguous. Explore this diagram and its other views →

The engine dependency map follows materials, pipelines and native handles behind these application entry points.

Creation, publication and retirement

Operation

Ownership after the operation

Consequence

Decode CPU input

Assets::Images::Decoded owns pixels; geometry upload accepts transient vertices.

CPU preparation can precede graphics initialization.

Create/upload through Resources::Provider

A fresh image or geometry handle owns the uploaded generation.

The call copies its transient input. Direct creation does not insert an asset-cache entry.

Publish into a cache, material, scene or frame

Each published owner retains its selected generation.

Replacing a cache entry does not rebind older materials or frames.

Release owners and collect

The last logical release allows native retirement; backend maintenance collects on graphics.

Clearing a cache is insufficient while another owner still retains that generation. Backend shutdown closes native use even if logical handles remain.

If an object stays resident, check application handles, caches, material/scene owners and published frames before investigating the native collector. The residency guide gives the complete owner chain and shutdown contract.

Uses

Consumer

Dependency

Integration boundary

Resources::Provider upload operations

Assets::Images::Decoded and Rendering::Geometry::Vertex2D

CPU inputs are borrowed only through the upload call. The colored-vertex and sampler operations are optional capabilities and reject when unsupported.

Shader/material loading

Assets::Shaders::Builder

A provider may supply this optional borrowed adapter; selected recipes require that capability. Shader definitions.

Provider/renderer domain observation

Rendering::GraphicsDomain

Domain availability describes native lifetime; native use still requires the original live graphics context and its owner. OpenGL ownership.

Catalogue/domain observation

Events and Diagnostics::DomainId

Weak event routes and copied identities describe changes without retaining the backend. A domain token owns observation state, not native resources.

Used by

Consumer

Resource operation or retained value

Responsibility

Assets Loading::Loader

Creates images, cell geometry and shader/material generations.

Publish entries on the active loading owner; preserve partial-publication semantics.

Text upload and GUI scene uploaders

Create glyph/UI images, geometry and materials.

Publish a complete replacement generation or scene while earlier ones remain retained.

Rendering materials and DrawPacket2D

Retain pipeline, geometry and image/sampler bindings.

Use those generations only in their original live graphics domain.

Runtime Context and GameRuntime

Own the provider adapter and coordinate renderer maintenance.

Settle accepted work and recycle frames before backend closure.

Contracts

Uploads copy transient pixels/vertices before returning. Uploaded contents are immutable: changed content requires another handle and explicit publication. Provider ownership and current-context checks apply even when the C++ handle is shared. A shared logical handle does not extend a closed native domain’s usability.

Managers support one active provider/loading-owner domain. Publication can be incremental and resource retirement is deferred; neither a cache lookup nor a handle destructor promises immediate allocation/deletion on the current thread.

Lifecycle

Initialize rendering before uploading. Keep provider/context dependencies alive through pending requests, simulation completion and frame recycling. Drop game handles while the backend is still live. Native shutdown collects tracked resources and closes the domain; surviving logical handles remain safe for destruction/CPU inspection but cannot draw through it. Partial-failure cleanup must close remaining native state without masking the original failure.

Execution

CPU decoding/preparation can run away from graphics. Creation/upload and native collection obey the selected backend’s graphics-owner/current-context rules. The OpenGL implementation queues retirement from final release and collects it on graphics; final shared-pointer release alone performs no GL operation.

Integration

On the platform owner after graphics initialization:

auto pixels = CE::Assets::Images::decode(image_path);
auto image = engine_.resources().create_image(pixels);

Both values own their contents. You may release/reuse pixels after the upload; retain image through the material or frame that needs it. For costly decode, prepare on a worker and send the owned result through platform dispatch instead.

Limits and further reading

The portable provider does not promise generic in-place mutation, atomic asset batches or residency budgets. Read the complete cache/publication/retirement contract, CPU lifetime guide, provider interface and OpenGL owner guide.