prometeu-runtime/discussion/workflow/plans/PLN-0036-host-desktop-frame-pacing-and-presentation.md

8.8 KiB

id ticket title status created completed tags
PLN-0036 perf-host-desktop-frame-pacing-and-presentation Plan - Host Desktop Frame Pacing and Presentation review 2026-04-20
perf
host
desktop
frame-pacing
presentation
debug

Briefing

Implement DEC-0019 by removing unconditional desktop redraw polling, introducing a canonical host-side frame-publication trigger, preserving the last visible frame during paused or idle states, and updating the normative specs to reflect the locked contract.

Decisions de Origem

  • DEC-0019 - Host Desktop Frame Pacing and Presentation

Alvo

Deliver a host desktop execution path where:

  • the winit loop no longer uses continuous polling by default;
  • redraw happens only after logical frame publication or explicit host-owned invalidation events;
  • RGB565 to RGBA8 conversion remains full-frame but only runs on demand;
  • paused, debugger-waiting, and no-cartridge states keep the last valid image without continuous redraw;
  • specs and tests match the accepted decision.

Escopo

  • Update the desktop host loop in crates/host/prometeu-host-desktop-winit/src/runner.rs.
  • Introduce or stabilize a canonical "new frame published" signal at the runtime-host boundary.
  • Track host-owned invalidation causes for overlay, debugger, and window events.
  • Update the relevant runtime specs under docs/specs/runtime/.
  • Add or extend automated tests for redraw gating and paused-state behavior.

Fora de Escopo

  • Dirty-region framebuffer conversion.
  • GPU/shader-based presentation paths.
  • New guest-visible ABI or debug surface.
  • Redesign of overlay visuals or debugger protocol beyond invalidation signaling.
  • Reopening the architecture covered by DEC-0019.

Plano de Execucao

Step 1 - Establish the canonical frame-publication trigger

What: Define the single host-consumable signal that indicates a new logical frame has been published.

How: Inspect the current buffer swap/publication point in the desktop runtime path and choose the existing internal publication event, dirty flag, or monotonic frame counter that can become the canonical trigger required by DEC-0019. If no stable signal exists, add a host-internal publication marker that changes exactly once per newly published logical frame and is not guest-visible.

File(s):

  • crates/host/prometeu-host-desktop-winit/src/runner.rs
  • any directly related runtime/firmware module discovered as the current frame-publication owner

Depends on: none

Step 2 - Replace unconditional redraw requests with invalidation-driven scheduling

What: Remove the unconditional redraw call from the idle loop and gate presentation on frame publication or host-owned invalidation.

How: Refactor about_to_wait() and redraw scheduling in runner.rs so the host requests redraw only when:

  • a new logical frame was published since the last presentation;
  • the window receives a visible invalidation event such as resize/expose;
  • overlay state toggles or changes a visible host-owned layer;
  • debugger-visible state changes require host-side recomposition.

Introduce explicit host-owned invalidation state if needed so redraw causes are tracked instead of inferred by polling.

File(s):

  • crates/host/prometeu-host-desktop-winit/src/runner.rs

Depends on: Step 1

Step 3 - Move the event loop from default Poll to deadline/event waiting

What: Change the normal desktop control flow so the host waits for the next logical deadline or external event instead of spinning continuously.

How: Update resumed() and any related loop control code in runner.rs to stop using ControlFlow::Poll as the default. Use WaitUntil when a next logical tick deadline is known and Wait when the host is effectively idle with no immediate timing deadline. Keep any aggressive polling path behind an explicit profiling-only switch rather than as baseline behavior.

File(s):

  • crates/host/prometeu-host-desktop-winit/src/runner.rs
  • crates/host/prometeu-host-desktop-winit/src/main.rs if a profiling-only opt-in flag is wired at startup

Depends on: Step 2

Step 4 - Preserve the last valid frame during paused, breakpoint, and no-cart states

What: Ensure non-running machine states do not cause repeated conversion/presentation work while still allowing host-owned UI recomposition when something visible changes.

How: Separate "machine produced a new frame" from "host-owned layer needs redraw". Keep the last presented RGBA output available for reuse, avoid logical buffer swaps during pause-only overlay activity, and ensure debugger waiting and no-cartridge states do not schedule continuous redraws. If overlay or debugger content changes while the machine is paused, redraw only the host-owned composition layer on explicit invalidation.

File(s):

  • crates/host/prometeu-host-desktop-winit/src/runner.rs
  • crates/host/prometeu-host-desktop-winit/src/overlay.rs
  • crates/host/prometeu-host-desktop-winit/src/debugger.rs

Depends on: Step 2

Step 5 - Update the normative specs

What: Propagate the accepted decision into the canonical runtime specs.

How: Update the portability and debug chapters so they explicitly state that desktop presentation observes published logical frames, that host-owned overlay/debug redraw is event-driven rather than continuously polled, and that stable host HUD state does not justify perpetual redraw. Keep the text aligned with the locked decision and do not introduce new architecture.

File(s):

  • docs/specs/runtime/10-debug-inspection-and-profiling.md
  • docs/specs/runtime/11-portability-and-cross-platform-execution.md

Depends on: Step 1

Step 6 - Add regression tests and evidence

What: Add automated coverage for the redraw contract and document manual evidence where platform events are hard to model.

How: Extend or add tests in the desktop host crate to cover:

  • no redraw request when no new frame and no host invalidation occurred;
  • redraw request after a newly published logical frame;
  • redraw request after overlay toggle or equivalent host-owned invalidation;
  • no continuous redraw in paused/debugger-waiting/no-cart states;
  • preservation of last visible frame semantics while paused.

Where direct winit event simulation is difficult, factor logic into testable state transitions and keep any remaining platform verification in a short manual checklist.

File(s):

  • crates/host/prometeu-host-desktop-winit/src/runner.rs
  • crates/host/prometeu-host-desktop-winit/src/overlay.rs if overlay invalidation helpers become testable
  • crates/host/prometeu-host-desktop-winit/src/debugger.rs if debugger invalidation hooks are exposed

Depends on: Steps 2, 3, 4

Criterios de Aceite

  • The default desktop event loop no longer runs in continuous ControlFlow::Poll.
  • The host requests redraw only after canonical frame publication or explicit host-owned invalidation.
  • Full-frame RGB565 to RGBA8 conversion remains in place but is not executed continuously while the visible machine frame is unchanged.
  • Paused, breakpoint, debugger-waiting, and no-cartridge states preserve the last valid image without continuous redraw.
  • Overlay or debugger changes can still trigger targeted host-owned redraw when visually necessary.
  • No guest-visible ABI is added for this feature.
  • The relevant runtime specs state the same redraw and presentation contract as DEC-0019.
  • Automated tests cover the main redraw gating paths and paused-state behavior.

Tests / Validacao

Unit Tests

  • Add focused tests for redraw scheduling state transitions in the desktop host runner.
  • Add tests for any helper that tracks frame-publication state or host-owned invalidation causes.

Integration Tests

  • Extend host crate tests to verify frame publication and debugger/overlay invalidation do not regress redraw policy.
  • Run cargo test -p prometeu-host-desktop-winit --lib.

Manual Verification

  • Launch the desktop host with overlay disabled and confirm CPU usage drops when the machine is visually stable.
  • Toggle overlay on and off and confirm redraw happens on the visible transition without restoring continuous polling.
  • Pause execution or wait for debugger start and confirm the last frame remains visible without repeated redraw.
  • Resize or expose the window and confirm the surface is recomposed correctly.

Riscos

  • The actual frame-publication point may be less explicit than assumed, requiring a small host-internal contract addition before redraw gating can be made reliable.
  • winit waiting semantics can introduce timing regressions if the next logical deadline is computed incorrectly.
  • Overlay or debugger code may currently assume redraw is always free, which can surface hidden invalidation bugs after polling is removed.
  • Manual verification may still be needed for some window-system invalidation behavior that is cumbersome to model in tests.