13 KiB
| id | ticket | title | status | created | ref_agenda | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DEC-0031 | vm-render-parallel-execution-boundary | VM and Render Parallel Execution Boundary | accepted | 2026-06-05 | AGD-0040 |
|
Status
Open decision draft generated from accepted agenda AGD-0040.
This decision is ready for review/acceptance. Once accepted, it becomes the normative contract for any spec or code plan that introduces a real render worker/core.
Contexto
DSC-0038 established RenderSubmission as a closed typed snapshot. That gives Prometeu the data boundary needed for future concurrency, but it did not define the operational contract for running VM/logical execution and render consumption on different threads/cores.
The current runtime consumes submissions synchronously through local Hardware/Gfx paths. Moving rasterization/presentation out of the VM path requires explicit rules for packet completeness, shared resources, handoff, pacing, lifecycle ownership, and telemetry.
Decisao
Prometeu SHALL treat VM execution and render consumption as separate responsibilities connected by closed render submissions.
For the first real asynchronous render model, the runtime SHALL use a single-slot latest-wins handoff for Game pipelines, paced by a frame scheduler, with render ownership guarded by epoch/generation and observable through telemetry. Shell/System UI SHALL remain lifecycle/event-driven and local/synchronous by default, while preserving the same closed-packet boundary.
This decision does not require implementing the worker immediately. It locks the architecture that any future worker implementation MUST follow.
Rationale
The design preserves the console/game timing model without allowing the VM to depend on render success. It also avoids an unbounded queue, stale frame presentation, mutable access to live VM/renderer state, and accidental treatment of Shell UI as a game renderer.
The decision keeps the first worker model small:
- the VM publishes at most one latest pending submission;
- the worker consumes owned immutable submissions;
- the frame scheduler, not render ACK, paces logical Game frames;
- lifecycle transitions invalidate stale visual ownership;
- telemetry reports drops/repeats/errors without changing VM semantics.
Invariantes / Contrato
1. Packet completo
RenderSubmissionPacket::Game2D MUST be a complete frame description for the render consumer.
The Game2D consumer MUST compose in this order:
Game2D composer / scene / layers / sprites
-> gfx2d primitives overlay
-> publication / present
The active-scene path MUST NOT bypass the packet or drop gfx2d. gfx2d primitives are a final overlay both with and without an active scene.
2. Recursos compartilhados
Packets crossing the VM/render boundary MUST remain small and owned. Heavy resources MUST NOT be copied into every submission.
The packet SHALL carry stable IDs/handles. Large resident resources such as glyph banks, scene banks, assets, and viewport cache materializations SHALL be accessed through read-only APIs.
The viewport cache belongs to the logical core. The render worker MAY read it through a read-only API after logical/core preparation has completed. Resolver updates, cache refreshes, asset installation, and bank residency changes MUST happen before handoff or in an owning service, not during worker rasterization.
The system does not guarantee visual integrity when a developer/framework swaps resources behind an in-flight submission in a way that violates asset discipline. Submissions refer to resource IDs; disciplined replacement is the responsibility of the developer/framework layer.
Any implementation that crosses a Rust thread boundary MUST prove the handoff and read-only resource APIs are safe for sharing. The worker MUST NOT receive &mut Hardware, &mut Gfx, live FrameComposer, or mutable VM/runtime state.
3. Handoff
The base handoff protocol SHALL be single-slot latest-wins.
The producer moves an owned closed submission into a pending slot. If the worker has not consumed that pending submission and the producer publishes a newer one, the newer submission replaces the older one. Replacement MUST be counted as a dropped/replaced-before-consume event.
The worker owns any submission it has taken from the slot. A currently-rendering submission is outside the pending slot.
The VM/producer MUST NOT block waiting for worker ACK, consumption, raster completion, or present completion. Worker consumed/presented status is telemetry only.
Shell UI is outside the worker protocol by default. A future configuration MAY reuse the same handoff for Shell, but that is not the default policy.
4. Frame pacing
Game logical frames SHALL be paced by a FrameClock/FrameScheduler authority, not by render-worker ACK.
The VM MUST NOT run freely ahead of display cadence. The target is one logical Game frame per frame tick and at most one pending submission ahead of the worker. The worker presents at display cadence, initially 60Hz where available, and repeats the last valid frame if no new valid submission exists.
FRAME_SYNC remains the canonical end of a VM logical frame. The old budget mechanism MUST NOT be used as the normal way to cut or advance a logical frame. Budget/cycle/time accounting remains for certification, watchdog, diagnostics, and overrun reporting.
If a logical frame exceeds the display window, logical frames remain sequential. The runtime records overrun/stutter and the worker repeats the last valid frame. The delayed submission represents the next sequential logical frame, not a skipped N+k frame.
Input sampling for Game SHOULD occur at the start of an authorized logical frame. Repeated presents without a new logical frame MUST NOT imply new input sampling or a hidden logical update.
5. Politica por AppMode / pipeline
Render execution policy SHALL be explicit by AppMode/pipeline.
Game workloads are frame-paced by definition. Current AppMode::Game and future explicit Game2D/Game3D modes SHALL use the frame scheduler and MAY use a render worker by default when the host/runtime supports it, with synchronous/local fallback.
Shell/System UI is lifecycle/event-driven. It MUST NOT inherit the Game logical frame loop. Shell UI SHALL publish local/synchronous by default and render by invalidation/event/lifecycle. Shell VM-backed apps follow Shell lifecycle and MUST NOT declare an independent frame-paced workload under this decision.
Firmware/system screens such as splash, crash, and hub follow Shell/local policy unless a later decision creates a more specific policy.
SystemOS/lifecycle decides the semantic profile/AppMode. RenderManager executes the render policy. Host/HAL provides capabilities and concrete execution.
6. Lifecycle, epoch e ownership
Every submission that may cross an asynchronous boundary MUST carry enough ownership context to reject stale presentation. This includes frame identity plus render ownership such as epoch/generation and owner/app/mode identity as needed.
Any foreground visual-owner transition SHALL increment/apply a render epoch or equivalent generation through a central RenderManager API. SystemOS/lifecycle decides that a semantic transition occurred; RenderManager applies the render ownership transition.
Transitions that MUST invalidate stale pending/current submissions include:
- Game -> Shell/Hub;
- Shell/Hub -> Game;
- crash screen;
- splash or system screen takeover;
- cartridge/app swap, even if
AppModeremains the same; - shutdown/stop.
The worker MAY finish raster work for an obsolete submission, but it MUST check epoch/owner before present and MUST NOT present frames that no longer match active ownership.
The same physical surface MAY be shared by Game, Shell, Hub, splash, and crash screens, but logical ownership MUST be explicit. On Shell -> Game, the runtime MAY keep the previous Shell/Hub surface visible until the first valid Game submission; clearing is a visual policy, not a correctness requirement.
Shutdown MUST stop presentation of obsolete work, discard pending submissions, invalidate current work through epoch/stop token, and terminate/join the worker in a bounded way. It MUST NOT drain obsolete frames to the screen.
Foreground stack, Game pause/resume, and coexistence of paused Game with VM-backed Shell apps are outside this decision and are tracked separately by DSC-0041.
7. Erros, drops e telemetria
Asynchronous render is observable best-effort, not a semantic handshake with the VM.
Render drops, repeated presents, stale-epoch discards, raster errors, and present errors MUST be reported through runtime/host telemetry. They MUST NOT directly alter VM program semantics, and VM code MUST NOT depend on "this frame was presented" to advance logic.
Minimum counters:
produced_submissions;replaced_before_consume;consumed_submissions;presented_frames;repeated_presents;render_errors;present_errors;stale_epoch_discards;shutdown_discards.
Minimum IDs/state:
last_produced_frame_id;last_consumed_frame_id;last_presented_frame_id;last_dropped_frame_id;last_error_frame_id;active_render_epoch.
Minimum events:
- submission replaced in the pending slot before consumption;
- worker consumed a submission;
- worker discarded a submission due to stale epoch/owner;
- worker presented a frame;
- worker repeated the last frame because no new valid submission existed;
- raster error;
- present error;
- shutdown/cancel discarded pending/current work.
Raster error on a submission SHOULD discard that submission, record telemetry, and preserve the last valid frame/current surface when possible. Present errors SHOULD record telemetry and MAY escalate to host/system fault policy if repeated. Worker panic MUST become controlled worker/backend failure and MUST NOT propagate as a VM panic.
Impactos
Spec
Specs need to describe:
- closed render packet completeness;
- handoff and pacing model;
- render ownership epoch/generation;
- AppMode/pipeline policy;
- minimum telemetry surface.
Runtime
RenderManager needs to become the central owner of render handoff, policy execution, epoch/generation, and render telemetry. It remains coordinator, not renderer.
Host / HAL
Host/HAL provides concrete execution capability: synchronous/local render, render worker thread, separate core, DMA/copresenter, or fallback. Host/HAL does not decide lifecycle ownership.
Firmware / SystemOS
SystemOS/lifecycle remains the semantic owner of mode/app/task transitions. Firmware state changes must route visual ownership transitions through the render ownership API when asynchronous render exists.
Tests
Plans derived from this decision must include tests for:
- active-scene Game2D preserving
gfx2doverlay after layer composition; - latest-wins replacement telemetry;
- stale epoch discard before present;
- Shell local/default policy remaining independent from Game pacing;
- logical frame overrun producing repeat/stutter telemetry without frame skip semantics.
Alternativas Descartadas
Fila crescente de submissions
Rejected because it increases latency, memory usage, and stale frame risk. The first worker model should not accumulate old frames.
Worker como dono do frame counter canonico
Rejected because it mixes pacing authority with raster/present completion. Frame cadence belongs to the frame scheduler; the worker is a consumer/presenter.
Shell sempre no render worker
Rejected because Shell/System UI is lifecycle/event-driven. Forcing worker usage adds complexity without clear benefit.
Capturar recursos pesados por frame
Rejected because it is expensive and makes resource lifetime policy obscure. Packets should carry IDs and use read-only resident resources.
ACK de present como parte da semantica da VM
Rejected because it couples deterministic VM progress to host/render timing and failure modes.
Referencias
AGD-0040: VM and Render Parallel Execution Boundary.DSC-0038/LSN-0047: typed render submissions preserve domain boundaries.DSC-0031/LSN-0040: AppMode separates Game and System/Shell profiles.DSC-0032/LSN-0041: SystemOS owns lifecycle semantics.DSC-0035/LSN-0044: Shell liveness depends on task-owned focused window.DSC-0036/LSN-0045: Hub UI slices prove lifecycle boundaries.DSC-0041: foreground stack, Game pause, and VM-backed Shell coexistence.
Propagacao Necessaria
- Create a plan before spec or code execution.
- First plan should probably separate immediate packet correctness from future worker infrastructure.
- Spec text must be in English.
- Lessons must be created only after execution publishes spec/code state.
Revision Log
- 2026-06-05: Initial decision draft generated from accepted
AGD-0040.