test(client): capture offscreen under gamescope, at the native 3440x1440
Two faults, one fix.
Captures were stealing the desktop. Only the golden path even tried to go
offscreen, via xvfb-run -- which is not installed here, so it took the
"using visible window" fallback; --screenshot and --movie never wrapped at
all. Every capture opened a Godot window on the machine Jeroen is working
and gaming on. Now a single wrapper covers all three paths.
gamescope, not the alternatives, for two independent reasons. It renders on
the real AMD GPU, and the goldens are pinned to this box's Mesa/AMD output
(T-1121 -- they do not port across rendering stacks), so xvfb-run's llvmpipe
would shift every pixel: offscreen must not silently mean a different
renderer. And it is the only installed option that lets the output size be
set. cage is also present and also GPU-backed, but it is a kiosk compositor
and forces its client to the headless output's default -- measured, a
960x540 request produced a 1280x720 PNG. A wrapper that quietly changes
resolution is worse than none here.
Worse, because resolution is not cosmetic on this map. D-255's extent
inversion makes the shorter viewport axis span exactly one cell of the rung,
so the viewport decides how much world a rung shows and at what cell count
-- a small capture is a DIFFERENT map, not a scaled one. 960x540 was also
16:9, so it never exercised the ultrawide aspect added in 21e263d0a, which
is the aspect actually in daily use. Raised to the panel's native 3440x1440.
It paid for itself immediately: at native, Ferrath Global reports
courses=375 drawn=0 -- every river culled, where the same build drew them at
960x540. Filed as T-1239. That is exactly the class of bug a too-small
capture hides.
Goldens are NOT regenerated here. They are stale across 15 commits already,
and blessing the current look before it has been reviewed is the trap this
suite just spent a day proving.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+35
-16
@@ -81,33 +81,52 @@ for name in c.get('scenarios', {}):
|
||||
|
||||
# -- Helpers -------------------------------------------------------------------
|
||||
|
||||
# Offscreen wrapper for EVERY capture path.
|
||||
#
|
||||
# Captures must never steal the desktop: this box is also the developer's own
|
||||
# session. Until 2026-08-06 only the golden path even tried, via xvfb-run —
|
||||
# which is not installed here, so it hit the "using visible window" fallback,
|
||||
# and --screenshot/--movie never wrapped at all. Every capture grabbed focus.
|
||||
#
|
||||
# gamescope is preferred, for two independent reasons:
|
||||
# 1. It renders on the REAL GPU. The goldens are pinned to this box's
|
||||
# Mesa/AMD output (T-1121 — they do not port across rendering stacks), and
|
||||
# xvfb-run would fall back to llvmpipe software rendering, shifting every
|
||||
# pixel. Offscreen must not mean a different renderer.
|
||||
# 2. It is the only option that lets us SET the output size. cage is also
|
||||
# installed and also GPU-backed, but it is a kiosk compositor: it forces
|
||||
# its client to the headless output's default 1280x720 and silently
|
||||
# overrides --resolution (measured — a 960x540 request produced a 1280x720
|
||||
# PNG). A wrapper that quietly changes resolution is worse than none,
|
||||
# because RESOLUTION is load-bearing here: D-255's extent inversion makes
|
||||
# the shorter viewport axis span exactly one cell of the rung, so window
|
||||
# size decides how much world a rung shows. cage is deliberately not used.
|
||||
CAPTURE_PREFIX=()
|
||||
if command -v gamescope >/dev/null 2>&1; then
|
||||
CAPTURE_PREFIX=(gamescope --backend headless -W "${RESOLUTION%x*}" -H "${RESOLUTION#*x}" --)
|
||||
elif command -v xvfb-run >/dev/null 2>&1; then
|
||||
echo "Note: gamescope not found — falling back to xvfb-run (software GL; goldens may drift)" >&2
|
||||
CAPTURE_PREFIX=(xvfb-run -a --server-args="-screen 0 ${RESOLUTION}x24")
|
||||
else
|
||||
echo "Warning: no offscreen compositor (gamescope/xvfb-run) — capturing in a VISIBLE window" >&2
|
||||
fi
|
||||
|
||||
godot_capture() {
|
||||
local mode_flag="$1" # --scenario or --flow
|
||||
local name="$2"
|
||||
local output="$3"
|
||||
local extra_args=("${@:4}")
|
||||
|
||||
"$GODOT" --rendering-driver opengl3 --fixed-fps 60 --resolution "$RESOLUTION" \
|
||||
"${CAPTURE_PREFIX[@]}" "$GODOT" --rendering-driver opengl3 --fixed-fps 60 \
|
||||
--resolution "$RESOLUTION" \
|
||||
--path "$ROOT/client" -s res://tests/visual_capture.gd -- \
|
||||
$mode_flag "$name" --output "$output" "${extra_args[@]}" 2>&1
|
||||
}
|
||||
|
||||
# Retained as the golden-path name; offscreen handling now lives in
|
||||
# godot_capture, so both paths get it.
|
||||
xvfb_capture() {
|
||||
local mode_flag="$1"
|
||||
local name="$2"
|
||||
local output="$3"
|
||||
local extra_args=("${@:4}")
|
||||
|
||||
# Try xvfb-run for deterministic captures
|
||||
if command -v xvfb-run >/dev/null 2>&1; then
|
||||
xvfb-run -a --server-args="-screen 0 ${RESOLUTION/x/x}x24" \
|
||||
"$GODOT" --rendering-driver opengl3 --fixed-fps 60 --resolution "$RESOLUTION" \
|
||||
--path "$ROOT/client" -s res://tests/visual_capture.gd -- \
|
||||
$mode_flag "$name" --output "$output" "${extra_args[@]}" 2>&1
|
||||
else
|
||||
echo "Warning: xvfb-run not found — using visible window" >&2
|
||||
godot_capture "$mode_flag" "$name" "$output" "${extra_args[@]}"
|
||||
fi
|
||||
godot_capture "$@"
|
||||
}
|
||||
|
||||
# -- Server lifecycle (live scenarios) -----------------------------------------
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"resolution": [960, 540],
|
||||
"resolution": [3440, 1440],
|
||||
"_comment_resolution": "Native panel resolution (3440x1440 ultrawide, 2.39:1) as of 2026-08-06, raised from 960x540. Not cosmetic: D-255's extent inversion makes the shorter viewport axis span exactly one cell of the rung, so the viewport decides how much world a rung shows and at what cell count — a small capture is a DIFFERENT map, not a scaled one. 960x540 was also 16:9, so it never exercised the ultrawide aspect path added in 21e263d0a, which is the aspect actually used daily. Captures run offscreen under gamescope at this size (see tests/run-visual); goldens must be regenerated whenever this changes.",
|
||||
"settle_frames": 30,
|
||||
"tolerance": 5,
|
||||
"max_diff_pct": 0.5,
|
||||
|
||||
Reference in New Issue
Block a user