Skip to content

[Renderer] Make the steady-state frame allocation-stable and upload-efficient #139

Description

@proggeramlug

Parent: #126
Corresponds to EN-056 in docs/tickets.md
Related: #30

Problem

The renderer still performs avoidable steady-state work: repeated full lighting-buffer uploads, per-frame bloom/pass bind-group allocation, frame-graph construction, and other allocations/uploads documented in EN-056. These costs become significant at 4K, with many materials/lights, and as new quality passes arrive. Previous eager bind-group caching produced a black frame because cache keys missed frame-order/resource-validity state (#30).

Outcome

An allocation-stable steady-state frame with dirty/range-based uploads, persistent pass resources, compiled frame plans, and correctness-backed cache keys.

Required instrumentation

Before optimizing, add per-frame counters/bytes/timers for:

  • CPU allocations in renderer prepare/submit where practical;
  • Queue::write_buffer/staging writes by resource and byte count;
  • bind group, pipeline, encoder, and transient physical-resource creation;
  • graph compile/build count;
  • lighting/material/instance records dirtied vs uploaded;
  • cache hit/miss/rebuild reason.

Expose counters through existing profiler output and reset them per frame.

Work breakdown

  1. Lighting uploads: separate per-frame/view data from light arrays; upload once after light collection or update dirty ranges, not the whole ~8–9 KB block repeatedly.
  2. Material/instance uploads: use stable GPU buffers, dirty ranges, and growth strategy; avoid rebuilding unchanged records.
  3. Frame plan: consume the compiled render-graph cache; configuration/uniform changes must not rebuild topology.
  4. Bind groups: cache only when all bound resource identities/generations and validity state are represented. Land one pass at a time with screenshot/intermediate-buffer diff.
  5. Transient allocations: reuse graph-planned physical resources across frames/resizes.
  6. Shader/pipeline creation: prove all steady-state variants are prewarmed or cached; report first-use compilation separately.

Do not cache views of rotating history textures under a key that omits history index/generation/write-validity.

Acceptance criteria

  • After warm-up in an unchanged Ultra Sponza frame, graph compiles, pipeline creations, and new physical texture/buffer allocations are zero.
  • Bind-group creation is zero or an explicitly justified bounded count; each remaining site is named.
  • Lighting upload count/bytes scale with actual dirty data and are no longer repeated 8–9 times per unchanged frame.
  • A static-scene 1,000-frame run has stable renderer-owned memory after caches warm.
  • Toggle/resize/history-index stress tests produce no black frames, stale resource reads, or validation errors.
  • Quality corpus remains within image tolerance after each cache migration.
  • Before/after P50/P95/P99 CPU render-submit time and total upload bytes are attached at 1080p and 4K, vsync off.

Likely files

  • native/shared/src/renderer/mod.rs, graph.rs, transient.rs, postfx_chain.rs
  • material/light/scene pass modules
  • native/shared/src/profiler.rs, staging.rs

Non-goals

Dependencies

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions