151 lines
8.1 KiB
Markdown
151 lines
8.1 KiB
Markdown
---
|
|
id: DEC-0016
|
|
ticket: deferred-overlay-and-primitive-composition
|
|
title: Deferred GFX Overlay Outside FrameComposer
|
|
status: accepted
|
|
created: 2026-04-18
|
|
accepted: 2026-04-18
|
|
agenda: AGD-0028
|
|
plans: [PLN-0026, PLN-0027, PLN-0028, PLN-0029]
|
|
tags: [gfx, runtime, render, frame-composer, overlay, primitives, hud]
|
|
---
|
|
|
|
## Status
|
|
|
|
Accepted.
|
|
|
|
## Contexto
|
|
|
|
`DEC-0014` and `DEC-0015` established `FrameComposer` as the canonical orchestration path for game-frame composition and exposed that orchestration publicly through `composer.*`.
|
|
|
|
That migration left `gfx.draw_text(...)` and other `gfx` primitives with their historical immediate-write behavior against the working framebuffer. Once the runtime moved to end-of-frame composition through `FrameComposer.render_frame()`, those immediate writes became unstable: scene-backed frame composition can rebuild the backbuffer after primitive calls have already touched it.
|
|
|
|
The resulting conflict is not about whether primitives should remain available. It is about their semantic place in the pipeline. The accepted direction of this thread is that `gfx` primitives are not part of the canonical game composition model. They are primarily for debug, quick visual instrumentation, and rapid artifacts, and they must remain agnostic to scene/tile/sprite/HUD composition.
|
|
|
|
Relevant performance context migrated from `AGD-0010` also remains in force:
|
|
|
|
- the renderer continues to be a destructive software framebuffer model, not a retained scene graph or GPU-style renderer;
|
|
- internal primitive fast paths remain desirable;
|
|
- memory growth must remain constrained for the handheld target;
|
|
- optimization of primitive execution must not alter observable semantics.
|
|
|
|
## Decisao
|
|
|
|
`gfx.*` primitives and text SHALL move to a deferred final overlay model that lives outside `FrameComposer`.
|
|
|
|
Normatively:
|
|
|
|
- `FrameComposer` SHALL remain responsible only for canonical game-frame composition:
|
|
- scene composition;
|
|
- sprite composition;
|
|
- canonical HUD composition when such a HUD stage exists.
|
|
- `FrameComposer` MUST NOT become the owner of debug/primitive overlay state.
|
|
- Public `gfx.*` primitives, including `gfx.draw_text(...)`, SHALL belong to a V1 `gfx` overlay/debug family.
|
|
- That overlay/debug family SHALL be deferred rather than written immediately as the stable operational contract.
|
|
- The deferred overlay/debug stage SHALL be drained after `hud_fade`.
|
|
- The deferred overlay/debug stage SHALL be above scene, sprites, and canonical HUD in final visual order.
|
|
- The no-scene path MUST preserve the same final overlay/debug semantics.
|
|
- `gfx.*` primitives MUST remain semantically separate from scene/tile/sprite/HUD composition.
|
|
- The implementation MUST preserve operational separation sufficient to prevent the canonical game pipeline from depending on transient primitive/debug state.
|
|
|
|
## Rationale
|
|
|
|
This decision keeps the architectural boundary clean.
|
|
|
|
`FrameComposer` exists to own the canonical game frame. Debug primitives do not belong to that contract. Pulling them into `FrameComposer` would make the orchestration service responsible for a second semantic domain with different goals:
|
|
|
|
- game composition must be deterministic and canonical;
|
|
- primitive/text overlay must be opportunistic, screen-space, and pipeline-agnostic.
|
|
|
|
Keeping overlay/debug outside `FrameComposer` also aligns with the stated product intent: these primitives are useful helpers, but they are not meant to become a second composition language for games.
|
|
|
|
Draining them after `hud_fade` preserves the user-visible requirement that debug/overlay content stay truly on top and legible. This is more faithful to the accepted intent than treating primitives as part of HUD or world composition.
|
|
|
|
Finally, separating semantic ownership still leaves room for implementation reuse. Raster backends, span paths, and buffer-writing helpers may still be shared internally, provided the public operational model remains separate.
|
|
|
|
## Invariantes / Contrato
|
|
|
|
### 1. Ownership Boundary
|
|
|
|
- `FrameComposer` MUST own only canonical game-frame composition.
|
|
- Primitive/debug overlay state MUST live outside `FrameComposer`.
|
|
- The canonical game pipeline MUST NOT depend on primitive/debug overlay state for correctness.
|
|
|
|
### 2. Overlay Semantics
|
|
|
|
- `gfx.draw_text(...)` and sibling `gfx` primitives SHALL be treated as deferred final overlay/debug operations.
|
|
- Immediate direct writes to `back` MUST NOT remain the stable operational contract for these primitives.
|
|
- Final overlay/debug output MUST appear after:
|
|
- scene composition;
|
|
- sprite composition;
|
|
- canonical HUD composition, if present;
|
|
- `scene_fade`;
|
|
- `hud_fade`.
|
|
|
|
### 3. Separation from Game Composition
|
|
|
|
- Primitive/debug overlay MUST NOT be reinterpreted as scene content.
|
|
- Primitive/debug overlay MUST NOT be reinterpreted as sprite content.
|
|
- Primitive/debug overlay MUST NOT be the vehicle for canonical HUD composition.
|
|
- The public `gfx.*` primitive surface SHALL remain pipeline-agnostic relative to `composer.*`.
|
|
|
|
### 4. Consistency Across Frame Paths
|
|
|
|
- The scene-bound path and no-scene path MUST expose the same final overlay/debug behavior.
|
|
- Users MUST NOT need to know whether a scene is bound for `gfx.*` primitives to appear as final overlay/debug content.
|
|
|
|
### 5. Internal Optimization Contract
|
|
|
|
- Internal fast paths for lines, spans, fills, clears, or similar primitive operations MAY be introduced.
|
|
- Such fast paths MUST preserve the observable deferred overlay/debug semantics.
|
|
- This decision DOES NOT require fine-grained dirtying or per-primitive-class invalidation in the first migration.
|
|
|
|
## Impactos
|
|
|
|
### Runtime / Drivers
|
|
|
|
- The runtime frame-end sequence must gain a distinct overlay/debug drain stage outside `FrameComposer`.
|
|
- `gfx.draw_text(...)` and peer primitives can no longer rely on stable immediate framebuffer writes once this migration lands.
|
|
|
|
### GFX Backend
|
|
|
|
- `Gfx` will need an explicit deferred overlay/debug command path or equivalent subsystem boundary.
|
|
- Shared raster helpers remain allowed, but the overlay/debug phase must stay semantically distinct from scene/sprite/HUD composition.
|
|
|
|
### FrameComposer
|
|
|
|
- `FrameComposer` must remain free of primitive/debug overlay ownership.
|
|
- Any future HUD integration must not collapse that boundary.
|
|
|
|
### Spec / Docs
|
|
|
|
- The canonical graphics/runtime spec must describe `gfx.*` primitives as deferred final overlay/debug operations rather than stable immediate backbuffer writes.
|
|
- Documentation that describes frame ordering must show overlay/debug after `hud_fade`.
|
|
|
|
### Performance Follow-up
|
|
|
|
- `AGD-0010` remains the home for broader renderer performance work, dirtying strategy, and low-level primitive optimization policy.
|
|
- Primitive optimization carried out under that thread must respect the normative separation established here.
|
|
|
|
## Referencias
|
|
|
|
- [AGD-0028-deferred-overlay-and-primitive-composition.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0028-deferred-overlay-and-primitive-composition.md)
|
|
- [AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md)
|
|
- [DEC-0014-frame-composer-render-integration.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/decisions/DEC-0014-frame-composer-render-integration.md)
|
|
- [DEC-0015-frame-composer-public-syscall-surface.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/decisions/DEC-0015-frame-composer-public-syscall-surface.md)
|
|
|
|
## Propagacao Necessaria
|
|
|
|
- A new implementation plan MUST be created before code changes.
|
|
- That plan MUST cover:
|
|
- deferred overlay/debug ownership outside `FrameComposer`;
|
|
- runtime frame-end ordering changes;
|
|
- no-scene path parity;
|
|
- spec/documentation updates for `gfx.*` primitive semantics.
|
|
- The implementation plan MUST NOT reopen the ownership boundary accepted here.
|
|
|
|
## Revision Log
|
|
|
|
- 2026-04-18: Initial accepted decision from `AGD-0028`.
|
|
- 2026-04-18: Linked implementation plan family `PLN-0026` through `PLN-0029`.
|