Skip to content

ENG2-P2-01: Dense scene storage: slot arrays + generational handles replacing FxHashMap iteration #712

Description

@aram-devdocs

Parent

  • Program: ENG2 — GoudEngine v2 Rebuild (see the pinned master tracking issue)
  • Phase / Milestone: Phase 2 — Render Core v2 (eng2-p2-render-core)
  • Batch / Group: Batch 2.1 — Foundations from RFC-0005, Group A
  • Runbook spec: docs/src/runbook/phases/phase-2.md (committed with the roadmap)

Summary

Replace the FxHashMap<u32, T> object/mesh/light/material/model tables in Renderer3D with dense Vec-backed slot arrays addressed by generation-checked handles, per the RFC-0005 storage decision.

Architecture Context

Layer: Layer 2 (Libs) — libs/graphics/renderer3d/ (see tools/lint_layers.rs — downward-only deps).
Modules/types touched:

  • goud_engine/src/libs/graphics/renderer3d/core/mod.rs — replace objects, instanced_meshes, particle_emitters, lights, materials, object_materials, skinned_meshes, models, model_instances, animation_players fields (all FxHashMap<u32, _>) with dense slot storage.
  • goud_engine/src/libs/graphics/renderer3d/render/mod.rs — frame scan currently iterates &self.objects (hash map); must iterate the new dense slots.
  • Every renderer3d/core_*.rs file that inserts/removes/looks up by u32 id (models, instances, primitives, static batch) — update to the new handle type.

Boundary constraints (only those that apply):

  • Raw GPU calls stay in libs/graphics/backend/ — no wgpu:: outside it.

Pattern to follow: RFC-0005 (ENG2-P0-09) storage decision; existing generational-handle patterns in ecs/ (Handle<T>) and assets/ (Handle<T>) — mirror the index+generation scheme, do not invent a third one.

Scope

  • Design and implement dense Vec-backed slot arrays with generation-checked handles for objects, instanced meshes, lights, materials, models, model instances, particle emitters, skinned meshes, animation players.
  • Replace every FxHashMap<u32, _> lookup/insert/remove call site in renderer3d/ with the new handle API.
  • Stale-handle lookups must fail validation (return None/error), never alias a reused slot.
  • Tests: spec test at goud_engine/tests/spec/ + unit/isolation coverage for the new code paths.
  • Docs/rules updates if this invalidates .agents/rules/graphics-patterns.md or docs/src/*.

Acceptance Criteria

  • Zero FxHashMap<u32, _> fields remain in renderer3d/core/mod.rs for the migrated collections (grep-gated).
  • Frame scan iterates dense slots directly (no hash lookups on the hot path).
  • A stale/reused handle test proves generation mismatch is detected, not aliased.
  • PERF (area:performance): cull_scaling bench (from ENG2-P0-03) shows no regression from the storage swap alone (informational baseline for later Phase 2 issues that build on this).
  • cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings clean; cargo test green; ./codegen.sh && git diff --exit-code (drift gate)

Breaking Change & Throne Follow-up

None — additive/internal. The u32 handle values returned to callers keep their external shape (still u32-based FFI ids); only internal storage changes. If the handle representation must change externally, treat as breaking and name the Throne follow-up in a rebased body before merge.

Blocked By

ENG2-P0-09 (RFC-0005 must decide dense-slot storage shape before this executes).

Files Likely Touched

  • New/Modified/Generated: goud_engine/src/libs/graphics/renderer3d/core/mod.rs, renderer3d/core_primitives.rs, renderer3d/core_models/, renderer3d/core_model_instances.rs, renderer3d/core_static_batch.rs, renderer3d/render/mod.rs

Agent Notes

  • renderer3d/core/mod.rs:54-93objects, instanced_meshes, particle_emitters, lights, materials, object_materials, skinned_meshes, models, model_instances, animation_players are all FxHashMap<u32, _> fields (verified in current source at these lines).
  • The frame scan iterates these hash maps directly (for (&id, obj) in &self.objects in render/mod.rs) — this is the O(total) cost this issue targets, though the culling decision itself moves upstream in ENG2-P2-02. This issue is about storage shape; P2-02 is about when culling runs.
  • This is the RFC-0005 (P0-09) foundation — do not start until that RFC lands; it decides dense-slot vs other storage shapes.

Verification

cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings
cargo test
./codegen.sh && git diff --exit-code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions