#!/usr/bin/env bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # verify-win32-display.sh - Display parity gate for Win32: what the window # shows must be the stage, at every window scale and on the full screen. # # The golden hashes gate the stage, never the display. The Win32 backend # keeps the frame in a DIB section and draws only the rectangles that # changed at each show, so a stale or misplaced rectangle would never reach # a hash. UBER's probe build (make win32 builds it, into build/win32/probe) # ends with P13, the battery verify-dvx-display.sh and # verify-win16-display.sh run, which after every step asks the backend # (jlHostWin32ProbeDisplayMismatch in src/hosted/win32/win32Backend.c) how # many pixels differ: the frame's against the stage, the window as the # shows left it against the window fully repainted, and that repaint # against GDI stretching the core's frame itself. Every count must be 0, # and every pixel must have been compared: 64000 for the frame, plus the # window's pixels twice. # # Each run is UBERPROB.EXE under Wine (scripts/lib/wineGate.sh, a # 1280x1024 screen) with JOEYLIB_SCALE / JOEYLIB_ASPECT / JOEYLIB_FULLSCREEN # set as the spec asks. It checks Wine's GDI, not a real Windows'. # # Usage: scripts/verify-win32-display.sh [SCALE[:square] | full]... # (default: 1:square 2:square 3 full) # Requires: Wine (install.sh install emulator:win32); # build/win32/probe/UBERPROB.EXE (make win32). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/wineGate.sh" label=verify-win32-display wineNeed folder=$repo/build/win32/probe program=$folder/UBERPROB.EXE log=$folder/joeylog.txt probeLine="UBER-PROBE: win32DisplayMismatch" doneLine="press any key to exit" stageWidth=320 stageHeight=200 stagePixels=$((stageWidth * stageHeight)) screenWidth=1280 screenHeight=1024 fullSpec=full runSeconds=120 # one probe run, start to done line defaults=(1:square 2:square 3 "$fullSpec") specs=("$@") [ ${#specs[@]} -gt 0 ] || specs=("${defaults[@]}") if [ ! -f "$program" ]; then echo "$label: the probe build is missing; run: make win32" >&2 exit 2 fi work="" cleanup() { wineStop [ -n "$work" ] && rm -rf "$work" } trap cleanup EXIT fails="" passed=0 # fail SPEC WHAT -- note a failed run; the gate goes on with the rest. fail() { echo "$label: FAIL - $1: $2" fails="${fails:+$fails; }$1" } for spec in "${specs[@]}"; do unset JOEYLIB_SCALE JOEYLIB_ASPECT JOEYLIB_FULLSCREEN if [ "$spec" = "$fullSpec" ]; then export JOEYLIB_FULLSCREEN=1 # 4:3 across the whole screen. w=$screenWidth h=$((screenWidth * 3 / 4)) elif [[ "$spec" =~ ^([0-9]+)(:square)?$ ]]; then scale=${BASH_REMATCH[1]} export JOEYLIB_SCALE=$scale w=$((stageWidth * scale)) if [ -n "${BASH_REMATCH[2]}" ]; then export JOEYLIB_ASPECT=square h=$((stageHeight * scale)) else h=$((w * 3 / 4)) fi else echo "$label: bad spec \"$spec\" (SCALE[:square] or $fullSpec)" >&2 exit 2 fi want=$((stagePixels + 2 * w * h)) wineStop [ -n "$work" ] && rm -rf "$work" work=$(mktemp -d -t joeylib-win32-display.XXXXXX) rm -f "$log" wineStart "$work" wineRun "$program" row="" for ((waited = 0; waited < runSeconds; waited++)); do if grep -q "$doneLine" "$log" 2> /dev/null; then row=$(grep -F "$probeLine" "$log" | tr -d '\r' | tail -1) break fi sleep 1 done if [ -z "$row" ]; then fail "$spec" "no \"$probeLine\" line within ${runSeconds} s" continue fi counts=${row#*"$probeLine" } echo "$label: $spec (${w}x${h}): $counts" bad=$(printf '%s\n' "$counts" | tr ' ' '\n' | grep '^after' | grep -v '=0$' | tr '\n' ' ') compared=$(printf '%s\n' "$counts" | sed -n 's/.*compared=\([0-9]*\).*/\1/p') if [ -n "$bad" ]; then fail "$spec" "pixels differ: $bad" elif [ "$compared" != "$want" ]; then fail "$spec" "compared $compared, want $want (is the window ${w}x${h}?)" else passed=$((passed + 1)) fi done if [ -n "$fails" ]; then echo "$label: FAIL - $fails" exit 1 fi echo "$label: PASS ($passed window sizes: every pixel shown matches the stage after every present)"