187 lines
7.7 KiB
Markdown
187 lines
7.7 KiB
Markdown
---
|
|
id: DEC-0014
|
|
ticket: render-all-scene-cache-and-camera-integration
|
|
title: Frame Composer Render Integration
|
|
status: accepted
|
|
created: 2026-04-14
|
|
accepted: 2026-04-14
|
|
agenda: AGD-0026
|
|
plans: [PLN-0017, PLN-0018, PLN-0019, PLN-0020, PLN-0021]
|
|
tags: [gfx, runtime, render, camera, scene, sprites]
|
|
---
|
|
|
|
## Status
|
|
|
|
Accepted.
|
|
|
|
## Contexto
|
|
|
|
`DSC-0025` closed the canonical scene model around `SceneBank`, `SceneViewportCache`, and `SceneViewportResolver`, but the operational frame loop still remained split. `Gfx` still exposed `render_all()`, while the new world path already existed separately as `render_scene_from_cache(...)`.
|
|
|
|
This left the runtime with an incomplete composition model:
|
|
|
|
- canonical scene/camera/cache architecture had already changed;
|
|
- the normal frame entrypoint had not yet been integrated with that architecture;
|
|
- sprite ownership was still too coupled to `Gfx` and to a slot-first `active` model.
|
|
|
|
This decision closes the ownership and composition model for the next integration phase.
|
|
|
|
## Decisao
|
|
|
|
The runtime SHALL converge to a `FrameComposer`-owned frame orchestration model.
|
|
|
|
Normatively:
|
|
|
|
- `Gfx.render_all()` MUST be retired as the canonical frame service.
|
|
- The canonical operational frame entrypoint SHALL become `FrameComposer.render_frame()`.
|
|
- `FrameComposer` SHALL live in `hardware/drivers`, alongside `Gfx`.
|
|
- `Hardware` SHALL aggregate both `FrameComposer` and `Gfx`.
|
|
- `FrameComposer` SHALL own the frame-operational state:
|
|
- active scene binding;
|
|
- camera / viewport state;
|
|
- `SceneViewportCache`;
|
|
- `SceneViewportResolver`;
|
|
- sprite submission state through `SpriteController`.
|
|
- `Gfx` SHALL remain a low-level visual backend responsible for composition, blit, and raster execution.
|
|
- `Gfx` MUST NOT remain the owner of scene state or sprite submission state.
|
|
|
|
## Rationale
|
|
|
|
This split preserves a clean ownership model:
|
|
|
|
- `FrameComposer` decides what the frame is;
|
|
- `Gfx` executes how the frame is drawn.
|
|
|
|
Keeping orchestration in `FrameComposer` avoids re-entangling renderer code with camera policy, cache refresh policy, and scene binding. Keeping `FrameComposer` in `hardware/drivers` instead of `hal` preserves room for backend-specific acceleration while avoiding a policy-heavy abstraction in HAL.
|
|
|
|
This also preserves future backend freedom:
|
|
|
|
- software path today;
|
|
- hardware-assisted blit path later;
|
|
- or a more PPU-like backend in bare-metal environments.
|
|
|
|
## Invariantes / Contrato
|
|
|
|
### 1. Frame Entry
|
|
|
|
- The canonical public frame orchestration path SHALL be `FrameComposer.render_frame()`.
|
|
- `FrameComposer.render_frame()` SHALL be capable of producing a valid frame 100% of the time.
|
|
- A valid frame MUST NOT require a scene to be bound.
|
|
|
|
### 2. No-Scene Behavior
|
|
|
|
- If no scene is bound, `FrameComposer.render_frame()` SHALL compose only:
|
|
- emitted sprites;
|
|
- fades already owned by the visual backend.
|
|
- No implicit clear SHALL be performed.
|
|
- Clearing the back buffer SHALL remain the responsibility of the caller / developer.
|
|
- In the no-scene state:
|
|
- cache MUST be absent or inert;
|
|
- resolver MUST be absent or inert;
|
|
- the system SHALL expose explicit scene-availability status.
|
|
|
|
### 3. Scene Binding
|
|
|
|
- Scene binding SHALL be performed by `bind_scene(scene_bank_id)`.
|
|
- `FrameComposer` SHALL depend on `SceneBankPoolAccess`.
|
|
- `FrameComposer` MUST resolve scenes through the pool, not through copied scene values.
|
|
- Scene access MUST be pointer-based / shared-reference based only.
|
|
- On bind, `FrameComposer` SHALL store:
|
|
- `scene_bank_id`;
|
|
- `Arc<SceneBank>` for the resolved scene.
|
|
- The `SceneViewportCache` SHALL live inside `FrameComposer` while the scene remains bound.
|
|
- `unbind_scene()` SHALL:
|
|
- remove the active scene;
|
|
- discard the associated cache;
|
|
- invalidate the world path;
|
|
- keep the frame path valid for no-scene composition.
|
|
- Replacing the contents of a bound scene slot SHALL require a new explicit bind.
|
|
- `FrameComposer` MUST NOT poll the scene bank pool each frame to revalidate the binding.
|
|
- A new `bind_scene(...)` SHALL replace the previous bound scene completely.
|
|
|
|
### 4. Camera
|
|
|
|
- The V1 camera contract SHALL be minimal.
|
|
- `set_camera(x, y)` SHALL accept `i32` pixel coordinates.
|
|
- `x` and `y` SHALL represent the top-left of the viewport in world space.
|
|
- Camera follow, smoothing, shake, cinematic transitions, and similar behaviors are OUT OF SCOPE for this decision.
|
|
|
|
### 5. Cache and Resolver
|
|
|
|
- `FrameComposer` SHALL own both `SceneViewportCache` and `SceneViewportResolver`.
|
|
- `FrameComposer` SHALL apply `CacheRefreshRequest`s to the cache.
|
|
- `Gfx` MUST NOT own cache refresh policy.
|
|
- `Gfx` MUST only consume already prepared render state.
|
|
|
|
### 6. Sprite Model
|
|
|
|
- `Sprite.active` MUST be removed from the canonical operational model.
|
|
- Sprite submission SHALL become frame-emission based.
|
|
- `SpriteController` SHALL be the sprite submission subsystem owned by `FrameComposer`.
|
|
- The sprite frame capacity SHALL remain capped at `512` for V1.
|
|
- The sprite counter SHALL be reset at the start of each frame.
|
|
- The caller MUST NOT provide sprite indices directly.
|
|
- Each `emit_sprite(...)` call SHALL occupy the next available internal slot.
|
|
- Overflow beyond capacity SHALL be ignored.
|
|
- Overflow SHOULD leave room for system logging / telemetry.
|
|
- Future certification MAY penalize sprite overflow, but that is not part of this decision.
|
|
- `emit_sprite(...)` SHALL NOT require a dedicated reset API beyond the normal frame lifecycle.
|
|
|
|
### 7. Sprite Ordering
|
|
|
|
- Each sprite SHALL carry:
|
|
- `layer`;
|
|
- `priority`.
|
|
- `layer` SHALL remain numeric for now.
|
|
- The sprite `layer` type SHALL match the scene layer reference type used by the scene model.
|
|
- Composition SHALL be layer-based.
|
|
- Within a layer:
|
|
- lower `priority` SHALL render first;
|
|
- ties SHALL resolve FIFO by emission order.
|
|
|
|
### 8. Composition Scope
|
|
|
|
- HUD integration is OUT OF SCOPE for the first integration phase covered by this decision.
|
|
- The first integration phase SHALL focus on:
|
|
- world scene path;
|
|
- sprites;
|
|
- fades.
|
|
|
|
## Impactos
|
|
|
|
### HAL
|
|
|
|
- `GfxBridge` and adjacent visual contracts will need to stop treating `render_all()` as the canonical operational frame path.
|
|
|
|
### Drivers / Hardware
|
|
|
|
- `Hardware` will need to aggregate `FrameComposer` next to `Gfx`.
|
|
- `Gfx` will need to lose ownership of scene/sprite operational state.
|
|
- Sprite submission state will need to move into `SpriteController`.
|
|
|
|
### Runtime / VM
|
|
|
|
- The VM runtime will eventually trigger frame composition through the new `FrameComposer` path rather than depending on `Gfx.render_all()`.
|
|
- The VM/runtime side should not own the detailed cache or scene orchestration policy directly once `FrameComposer` exists in hardware/drivers.
|
|
|
|
### Asset / Scene Flow
|
|
|
|
- Scene activation will become explicit through bank-id binding.
|
|
- Scene slot replacement will require explicit rebinding behavior from callers.
|
|
|
|
## Referencias
|
|
|
|
- [AGD-0026-render-all-scene-cache-and-camera-integration.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0026-render-all-scene-cache-and-camera-integration.md)
|
|
- [LSN-0030-canonical-scene-cache-and-resolver-split.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/lessons/DSC-0025-scene-bank-and-viewport-cache-refactor/LSN-0030-canonical-scene-cache-and-resolver-split.md)
|
|
|
|
## Propagacao Necessaria
|
|
|
|
- A new implementation plan MUST be created from this decision before code changes.
|
|
- `FrameComposer` and `SpriteController` need explicit planning and migration sequencing.
|
|
- `Gfx.render_all()` retirement MUST be planned rather than removed ad hoc.
|
|
- The frame service rename and integration path MUST be propagated through the frame loop callsites.
|
|
|
|
## Revision Log
|
|
|
|
- 2026-04-14: Initial accepted decision from `AGD-0026`.
|