diff --git a/docs/plans/2026-07-24-modern-runtime-architecture.md b/docs/plans/2026-07-24-modern-runtime-architecture.md index d822cc6d..36d37a04 100644 --- a/docs/plans/2026-07-24-modern-runtime-architecture.md +++ b/docs/plans/2026-07-24-modern-runtime-architecture.md @@ -1096,6 +1096,10 @@ per-session incremental memory given a numeric ceiling at gate time. ### Slice L — Linux graphical host and evidence-gated GPU work +**Prepared execution plan:** +[`2026-07-26-modern-runtime-slice-l.md`](2026-07-26-modern-runtime-slice-l.md). +Implementation begins after Slice K closes. + **Purpose:** Finish platform portability and only then pursue remaining GPU opportunities. diff --git a/docs/plans/2026-07-26-modern-runtime-slice-l.md b/docs/plans/2026-07-26-modern-runtime-slice-l.md new file mode 100644 index 00000000..1f27af34 --- /dev/null +++ b/docs/plans/2026-07-26-modern-runtime-slice-l.md @@ -0,0 +1,297 @@ +# Modern runtime Slice L — Linux graphical host and evidence-gated GPU work + +**Status:** PREPARED — BEGINS AFTER SLICE K CLOSEOUT +**Parent:** `2026-07-24-modern-runtime-architecture.md`, Slice L +**Authorization:** the user approved Slices F–L on 2026-07-24 +**Purpose:** ship the existing modern OpenGL client on supported Linux drivers +with identical Runtime behavior and accepted visual presentation, then make +only GPU changes whose measured bottleneck and visual equivalence are proven. + +## 1. Entry contract + +Slice L begins only after Slice K proves Linux Runtime/Core.Net/Content, +portable paths/config/credentials, one production headless host, deterministic +wire timing, shared immutable content, and a clean 30-session stress gate. + +L does not fork the game client into a second Linux implementation. The same +`AcDream.App`, `GameRuntime`, retained UI, rendering pipeline, shaders, and +resource owners run on both platforms. Platform-specific behavior is confined +to typed host services selected once at startup. + +## 2. Mandatory renderer boundary + +The modern path remains mandatory: + +- OpenGL 4.3 core; +- `GL_ARB_bindless_texture`; +- `GL_ARB_shader_draw_parameters`; +- the current bindless texture/SSBO/MDI layouts and shaders. + +There is no legacy renderer, texture-unit fallback, reduced-distance mode, or +platform-specific gameplay/render path. An unsupported driver fails startup +with a precise capability report. + +Driver acceptance begins with a committed matrix: + +- AMD Mesa/RadeonSI on X11; +- AMD Mesa/RadeonSI on Wayland; +- NVIDIA proprietary driver on X11; +- NVIDIA proprietary driver on Wayland where Silk's backend is supported; +- Intel only if the hardware/driver exposes every mandatory extension. + +Each row records distribution/kernel, display protocol, compositor, GPU, +driver, OpenGL vendor/renderer/version, extension presence, swap interval, +monitor refresh, and audio backend. A row may be “unsupported” only because a +mandatory capability is absent or the native window backend cannot create the +required context—not because a visual mismatch was waived. + +## 3. Initial platform inventory + +Portable foundations already exist: + +- Silk.NET owns window/input/OpenGL APIs; +- OpenAL Soft is designed for PulseAudio/PipeWire/CoreAudio as well as Windows; +- shader and UI asset paths use `AppContext.BaseDirectory`/`Path.Combine`; +- `BitmapFont.TryLoadSystemMonospaceFont` already includes common Linux font + paths; +- Runtime/Core.Net/Content are presentation-independent after J/K. + +Known Linux blockers and audit targets: + +- `FramePacingController` unconditionally constructs + `WindowsHighResolutionFramePacingWaiter`, which throws off Windows. +- The OpenAL Soft native package/runtime assets must be verified for each + Linux RID rather than assumed. +- Silk window backend/native dependency publication is not packaged or tested. +- the smoke-plugin MSBuild copy target uses Windows path separators; +- key bindings, cursor creation, clipboard, relative mouse, monitor refresh, + window-state callbacks, and high-DPI scaling need live X11/Wayland evidence; +- settings, layouts, keymaps, logs, screenshots, and diagnostics must use the + portable path owner established in K rather than `%LOCALAPPDATA%` wording or + ad hoc paths; +- no Linux graphical CI/smoke environment exists; +- no Linux driver timer-query validation or screenshot baseline exists; +- no package/install/uninstall contract exists. + +## 4. Platform-service contracts + +### Frame pacing + +Keep the existing display-aware policy: + +- VSync uses the driver's swap wait. +- VSync-off normal play uses a refresh-matched low-CPU software deadline. +- explicit uncapped diagnostics perform no wait. + +Replace direct Windows construction with `IFramePacingWaiterFactory`. +Windows retains the high-resolution waitable timer. Linux uses an +absolute-monotonic deadline wait (`clock_nanosleep` or a proven equivalent) +with cancellation-safe disposal. Neither path busy-spins for the normal wait. +The same missed-deadline rebase rule prevents catch-up bursts. + +Gate both waiters for deadline error, CPU usage, cancellation, disposal, missed +deadlines, monitor changes, and long stalls. + +### Paths and persistence + +Reuse K's portable path owner for: + +- settings and key bindings; +- retained UI layouts; +- logs and diagnostic captures; +- screenshots and automation artifacts; +- plugins; +- prepared assets and DAT location overrides. + +No feature reads a Windows-only environment variable/path at its call site. + +### Input/window + +Test the exact retained-input pipeline on X11 and Wayland: + +- keyboard keys, modifiers, text input, repeat, and configurable bindings; +- mouse buttons, wheel, press-time selection, dragging, resizing, and cursors; +- relative mouse capture, recenter/release, and focus loss; +- clipboard; +- window move/resize/minimize/restore/close and monitor transition; +- DPI/framebuffer size versus logical size. + +Retail input behavior remains the acceptance oracle; Linux key/scancode +adaptation cannot alter action semantics. + +### Audio + +OpenAL initialization remains fail-open only for the existing explicit +no-audio mode or unavailable device. Package the correct OpenAL Soft native +asset, identify PulseAudio/PipeWire device/context selection, and prove +source/buffer/context teardown. Audio absence must not stall the frame or +change Runtime/VFX timing. + +## 5. Packaging contract + +Produce repeatable `linux-x64` artifacts first; add `linux-arm64` only after +the complete native dependency and GL extension matrix passes. + +Artifacts contain: + +- the App and managed dependency closure; +- Silk window/input/OpenGL native dependencies; +- OpenAL Soft; +- shaders and retained-UI XML; +- plugin directory/manifest support; +- a launch entry point and version/provenance record. + +DATs, account credentials, and the machine-local `acdream.pak` are not bundled. +Startup diagnostics identify their configured paths without exposing secrets. + +Provide: + +- framework-dependent development publish; +- self-contained release publish if native/runtime size and licenses are + acceptable; +- desktop entry/icon/install documentation; +- package validation on a clean Linux user account. + +## 6. Execution + +### L0 — platform services and Linux build + +- Add Linux App build/publish jobs to CI after K's non-graphical Linux jobs. +- Add typed platform capability, path, pacing, and native-dependency owners. +- Implement the Linux monotonic frame waiter and factory selection. +- Correct cross-platform MSBuild paths and packaging assumptions. +- Add source/dependency guards against platform checks outside platform-owner + classes. + +Gate: App restores/builds/publishes for `linux-x64`; unit tests prove both +frame waiters and portable paths; no Windows P/Invoke executes on Linux. + +### L1 — context, extensions, and native backends + +- Create a Linux window and OpenGL 4.3 core context under X11 and Wayland. +- Capture the full capability record before renderer construction. +- Verify mandatory bindless and shader-draw-parameter calls, MDI, SSBOs, + persistent resource ownership, timer queries, framebuffer sRGB/depth/stencil, + and swap behavior. +- Initialize input and OpenAL Soft. +- Fail unsupported rows with one actionable diagnostic. + +Gate: a packaged smoke scene opens, renders, accepts input, plays optional +audio, captures a screenshot, and shuts down with zero GL/OpenAL/window debt on +each supported matrix row. + +### L2 — complete graphical connected route + +- Run the same exact-binary lifecycle/reconnect route used on Windows. +- Run the canonical nine-stop route with movement, jump, combat, portal, + revisit, and graceful shutdown. +- Verify radar, retained UI, inventory paperdoll, Use/approach, combat facing, + spell effects, portal tunnel/materialization/exit, cursors, chat, and audio. +- Compare pinned-camera images against accepted Windows references using the + existing per-channel tolerance and differing-pixel-fraction rule. +- Record CPU/GPU frame history, allocation, managed/native/GPU residency, + handles, threads, and driver facts. + +Gate: lifecycle/resource invariants and retail behavior match; screenshot +differences are within the committed driver-aware threshold and individually +inspected; no resource growth survives repeated portals. + +### L3 — packaging and clean-machine gate + +- Publish versioned Linux artifacts. +- Test install, first launch, configuration discovery, plugin discovery, + upgrade, and uninstall on a clean user account. +- Prove no implicit write occurs beside a read-only installed binary. +- Prove missing DAT/pak/driver/audio conditions produce actionable, + credential-safe errors. + +Gate: a clean machine reaches world, completes the route, exits gracefully, +and preserves settings/layout/key bindings under XDG paths. + +### L4 — accurate Linux profiling + +- Validate GL timer-query attribution on each accepted driver. +- Capture capped and uncapped canonical route, dense-town, portal-window, and + long-duration profiles on a physical local display. +- Attribute CPU update, render submission, GPU passes, allocations, upload, + particle, light, culling, and command-compaction costs. +- Compare Windows and Linux without mixing RDP/display protocol populations. + +Gate: the dominant remaining CPU/GPU stages are named with reliable samples. +If no GPU stage is material, do not migrate work merely because the roadmap +lists candidates. + +### L5 — evidence-gated GPU changes + +For each candidate independently: + +1. show it is a dominant stage in L4 evidence; +2. write a focused plan with ownership, synchronization, fallback/error, and + teardown contracts; +3. implement one bisectable change; +4. run deterministic/Release/connected/resource gates; +5. publish CPU and GPU before/after plus visual equivalence; +6. keep the change only if the intended metric materially improves without + regressions. + +Candidate order, only when evidence supports it: + +- GPU visibility culling; +- indirect command compaction; +- particle simulation; +- bounded light selection. + +No candidate changes server authority, physics, animation ordering, DAT effect +semantics, retained UI, or visible draw range. + +### L6 — closeout + +- Repeat the accepted Linux driver, packaging, connected, screenshot, + resource, and performance matrices. +- Run Windows regression gates. +- Audit every GPU migration and exact rollback. +- Update architecture, milestones, roadmap, issues/divergences, + AGENTS/CLAUDE, and durable memory. + +Gate: supported Linux graphical artifacts ship the same intended client +behavior; every retained GPU change has measured evidence and visual parity; +all teardown ledgers converge. + +## 7. Adversarial matrix + +- X11 versus Wayland, compositor on/off where practical; +- AMD versus NVIDIA extension/function-pointer behavior; +- mandatory extension advertised but call returns invalid handle/error; +- no display, no audio device, missing font, missing clipboard service; +- monitor hotplug, refresh change, DPI change, minimize, suspend/resume, focus + loss, and close during portal; +- VSync ignored, adaptive sync, software pacing stall, timer interruption, and + clock discontinuity; +- read-only install directory and XDG paths with spaces/non-ASCII; +- missing/corrupt pak, DAT mismatch, plugin failure, shader compile failure; +- GL context loss/failure during construction and teardown; +- audio context/buffer/source partial construction failure; +- screenshot differences from gamma, texture filtering, precision, clip + origin, or driver shader compilation; +- GPU migration overflow, indirect count mismatch, fence delay, stale + generation, device reset, and visibility false-negative; +- Windows regression after each platform abstraction. + +## 8. Non-goals + +- No legacy renderer or extension fallback. +- No reduced visual distance or Linux-specific quality default. +- No renderer rewrite solely for portability. +- No GPU migration without measured dominance. +- No macOS graphical support in Slice L; the portable Runtime/headless work and + typed platform services should make a later macOS plan smaller, but Apple + OpenGL capability constraints require a separate decision. +- No bundled DAT files, credentials, or local server. + +## 9. Commit and rollback discipline + +Land L0–L6 as separate buildable commits. Record the full production SHA and +exact `git revert ` after each focused/Linux/Windows/connected/visual +gate. GPU candidates each receive their own plan, commit, measurement, visual +gate, and rollback; rejected experiments are reverted rather than hidden +behind dormant alternate paths.