Slice 5+6 of the display block, one coherent unit (they share the state machine the goal's dual review covers). GlfwDisplayModeSwitcher (#376) ports retail's fullscreen semantics - Device::ForceDisplayResolution @gmClient::Init 0x004047af is a REAL video-mode change - through native glfwSetWindowMonitor on the same IWindow.Native.Glfw handle path #348's cursor cache proved. Primary monitor (retail's primary display device); refresh = the monitor's highest for the picked WxH; the windowed placement is remembered for the exit path; every failure is a no-throw (bool, reason) result. SilkRuntimeDisplayWindowTarget.Apply (#388) becomes the state-aware machine: fullscreen target = validated native mode switch (mode must be in #391's DisplayModeCatalog - an offered mode is supported by construction, making the "Graphics mode not supported" crash class unreachable from the dropdown); windowed target while fullscreen = the native exit (which sets the client size itself); plain windowed pick = the proven #387 size write. A raw Size write NEVER happens against a fullscreen window - on GLFW that is a video-mode request, and an unsupported one was the exact unhandled-GlfwException that killed the user's 2026-08-13 session. The old Silk borderless WindowState path is deleted from the apply. New IWindowedSizeSurface narrows the window dependency so the machine is unit-testable (FakePacingSurface idiom). Live-verified on this machine (goal-sanctioned automated run): display: fullscreen mode switch 1920x1080@300 -> framebuffer resize event 1920x1080 -> vulkan: swapchain recreated 1920x1080 ok=True -> graceful close, desktop mode restored. Tests: 5 state-machine facts (validated switch/never-size-write, unoffered refusal, failed-switch usability, native exit, plain windowed write). App suite 4,972/3 skips. Gate script sections D4-D6 written (black-screen-risk steps flagged). Dual Opus review of the pair follows as its own round. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
115 lines
6 KiB
Markdown
115 lines
6 KiB
Markdown
# Display & resolution block — connected-gate test script
|
||
|
||
**Status: slices D1 (#389 FOV) and D2 (#391 curated list) are LANDED and
|
||
testable now; D3 (#390 UI reposition) and D4–D6 (fullscreen family
|
||
#377/#376/#388) fill in as they land.** Launch with `ACDREAM_RETAIL_UI=1`
|
||
against local ACE, **Release** build for anything you judge by feel or
|
||
frame rate. The resize/display chain logs evidence permanently — after any
|
||
step you can cross-check `display: resolution pick`, `window: framebuffer
|
||
resize event`, and `vulkan: swapchain recreated` lines in the launch log.
|
||
|
||
---
|
||
|
||
## §D1 — Widescreen FOV feel (#389, SmartboxFOV)
|
||
|
||
The world camera now uses retail's law: your horizontal view stays roughly
|
||
constant (~84° at 16:9) and wide screens trim the vertical slice instead of
|
||
bloating the sides. Your stored Field of View migrates 60 → 90 (the retail
|
||
default) on first load.
|
||
|
||
1. **Just look at the world** on your 16:9 window at your usual spot
|
||
(Holtburg outdoors is ideal). Compared to yesterday: the view should
|
||
feel slightly more "zoomed"/framed — retail's framing — rather than the
|
||
old wide-angle look. If you have retail side-by-side, the framing should
|
||
now match it at the same window shape.
|
||
2. **Resize the window across shapes** (drag it narrow, then wide). The
|
||
world must stay geometrically true at every shape — no squish, no
|
||
stretch, circles stay circles (pre-#389, mid-session resizes distorted
|
||
the world in chase mode; that bug is dead).
|
||
3. **F11 → Config → Field of View slider.** It now means retail's gameFOV
|
||
in degrees (10–160, default 90) and applies LIVE as you drag —
|
||
the world widens/narrows immediately, no restart. Defaults restores 90.
|
||
4. Set it back to 90 when done (or click Defaults).
|
||
|
||
## §D2 — Curated resolution list (#391)
|
||
|
||
1. **F11 → Config → Resolution dropdown.** The list is now your monitor's
|
||
real modes, modern widescreen only: no 800x600, no 1024x768, nothing
|
||
your 2560x1440 desktop can't host (no 3840x2160 entry). Expect roughly:
|
||
1280x720 / 1366x768 / 1600x900 / 1920x1080 / 2560x1440 — exactly what
|
||
your monitor reports, one entry per size.
|
||
2. **Pick a few.** Every pick must land exactly (window resizes AND
|
||
re-renders crisp — §the #387 chain), including 2560x1440.
|
||
3. **Click Defaults.** The Resolution row restores **2560x1440** (your
|
||
desktop's own mode — the deliberate replacement for retail's 800x600
|
||
default; register row IA-22), and the dropdown shows it selected.
|
||
|
||
## §D3 — UI windows stay reachable on downscale (#390)
|
||
|
||
Retail's rule, ported exactly: on a display change every floating window
|
||
re-clamps to `x = max(0, min(x, screenW − windowW))` — top-left priority —
|
||
and the per-resolution saved layout for the NEW size reloads (without
|
||
saving anything until you save).
|
||
|
||
1. **At 2560x1440, drag several windows to the edges** — chat to the
|
||
bottom-right corner, the Options panel far right, a floating chat too.
|
||
2. **Pick 1280x720 in the Resolution dropdown.** Every window must end up
|
||
fully inside the new screen — anything that was past the new bounds
|
||
slides in flush with the edge; nothing needs a window-resize to fetch
|
||
back. (This includes floating chat windows — retail actually strands
|
||
those; we clamp them by the block's own requirement, register AD-91.)
|
||
3. **Drag-resize the window edge smaller** (not via the dropdown). Windows
|
||
must stay reachable continuously while you drag — the clamp runs live.
|
||
4. **Per-resolution memory:** at 1280x720 move a window somewhere
|
||
distinctive, pick 2560x1440, then pick 1280x720 again — the window
|
||
returns to where 1280x720 last had it (each resolution keeps its own
|
||
layout, like retail's per-resolution auto layouts — YOUR drags save
|
||
immediately under the current resolution; the automatic clamp/reload on
|
||
a resolution change never writes anything).
|
||
|
||
## §D4 — Fullscreen startup (#377)
|
||
|
||
1. **F11 → Config → tick Full Screen, then close the client and relaunch.**
|
||
The client must come up fullscreen at your saved resolution, no crash
|
||
(the old startup access-violation is 3/3-clean on current code, plus one
|
||
automated fullscreen boot verified live).
|
||
|
||
## §D5 — Real display-mode switching (#376) **[BLACK-SCREEN RISK]**
|
||
|
||
Every step here changes your monitor's actual video mode — the panel will
|
||
blank/re-sync for a moment each time. If a switch ever leaves the screen
|
||
black for more than ~5 seconds, Alt+F4 closes the client gracefully and
|
||
the desktop mode restores.
|
||
|
||
1. **Windowed at 1920x1080 → tick Full Screen.** The display itself
|
||
switches to 1920x1080 (at your monitor's highest refresh for that mode —
|
||
this panel reports 300 Hz): everything gets larger-grained, the monitor
|
||
re-syncs. This is retail's fullscreen, not a stretched borderless
|
||
window. Automated evidence for this step already exists
|
||
(`display: fullscreen mode switch 1920x1080@300` →
|
||
`vulkan: swapchain recreated 1920x1080`).
|
||
2. **While fullscreen, pick a different resolution** (e.g. 2560x1440). The
|
||
DISPLAY switches modes again — a real re-sync, crisp at the new mode,
|
||
never a scaled image.
|
||
3. **Untick Full Screen.** The desktop returns to its native mode and the
|
||
client becomes a normal window at your picked resolution, positioned
|
||
where it was before entering fullscreen.
|
||
|
||
## §D6 — No settings apply may crash the client (#388)
|
||
|
||
1. **Repeat your original crash recipe:** while fullscreen, change
|
||
resolution a few times quickly, toggle Full Screen off and on, drag
|
||
sliders in between. The client must never die — any refused/failed
|
||
switch logs a `display: ... failed/refused` line and leaves you in a
|
||
usable window instead.
|
||
2. The old crash's exact mechanism (a window-resize applied to a
|
||
fullscreen window becoming an unsupported video-mode request) is now
|
||
structurally impossible: fullscreen applies only validated modes from
|
||
the dropdown's own list, and size writes never touch a fullscreen
|
||
window.
|
||
|
||
---
|
||
|
||
**Carried context for the gate:** the FPS cost of large windows is real
|
||
physics (more pixels = more GPU work) — judge frame rate in Release only.
|
||
The title bar shows live FPS.
|