prometeu-runtime/discussion/workflow/decisions/DEC-0016-deferred-gfx-overlay-outside-frame-composer.md

8.1 KiB

id ticket title status created accepted agenda plans tags
DEC-0016 deferred-overlay-and-primitive-composition Deferred GFX Overlay Outside FrameComposer accepted 2026-04-18 2026-04-18 AGD-0028
PLN-0026
PLN-0027
PLN-0028
PLN-0029
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

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.