joeylib2/scripts/verify-win16-display.sh
2026-10-19 15:46:47 -05:00

172 lines
6.3 KiB
Bash
Executable file

#!/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-win16-display.sh - Display parity gate for Win16: 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 Win16 backend
# draws only the rectangles that changed at each show, scaling them itself,
# so a stale or misplaced rectangle would never reach a hash. UBER's probe
# build (make win16 builds it, into build/win16/probe) ends with P13, the
# battery verify-dvx-display.sh runs on DVX, which after every step asks the
# backend (jlHostWin16ProbeDisplayMismatch in src/hosted/win16/win16Backend.c)
# how many pixels differ: the frame's against the stage, the window as the
# shows left it against the window fully repainted, and, at a whole-number
# scale, that repaint against GDI's own stretch of the frame. In the
# identity layout (a palette display, 14 palettes in use or fewer) it also
# checks every window pixel's screen index against the frame's and every
# color of the palettes in use against the system palette, which is where
# an animated color change shows (its win16Layout line gives that count).
# Every count must be 0, and every pixel must have been compared: 64000 for
# the frame, plus the window's pixels once, or twice at a whole-number
# scale, plus the identity checks.
#
# Each run is UBERPROB.EXE on Windows 3.11 under DOSBox
# (scripts/lib/win16Gate.sh) with JOEYLIB_SCALE / JOEYLIB_ASPECT /
# JOEYLIB_FULLSCREEN set as the spec asks, on its 800x600 desktop. With the
# wing component installed every spec runs twice, its Windows with WinG and
# without (WIN16_WING), and the probe must say it drew the window that way:
# through WinG's canvas, or through device bitmaps.
#
# Usage: scripts/verify-win16-display.sh [SCALE[:square] | full]...
# (default: 1:square 2:square 2 full)
# Requires: Windows on DOSBox (install.sh install emulator:win16);
# build/win16/probe/UBERPROB.EXE (make win16).
set -uo pipefail
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source "$repo/scripts/lib/joeyEnv.sh"
source "$repo/scripts/lib/win16Gate.sh"
label=verify-win16-display
win16Need
folder=$repo/build/win16/probe
program=UBERPROB.EXE
probeLine="UBER-PROBE: win16DisplayMismatch"
layoutLine="UBER-PROBE: win16Layout"
doneLine="press any key to exit"
stageWidth=320
stageHeight=200
stagePixels=$((stageWidth * stageHeight))
desktopWidth=800
desktopHeight=600
fullSpec=full
runSeconds=120 # one probe run, boot to done line
defaults=(1:square 2:square 2 "$fullSpec")
specs=("$@")
[ ${#specs[@]} -gt 0 ] || specs=("${defaults[@]}")
if [ ! -f "$folder/$program" ]; then
echo "$label: the probe build is missing; run: make win16" >&2
exit 2
fi
work=""
cleanup() {
win16Stop
[ -n "$work" ] && rm -rf "$work"
}
trap cleanup EXIT
fails=""
passed=0
wingModes=(0)
[ "$WIN16_WING" = "1" ] && wingModes=(1 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 wing in "${wingModes[@]}"; do
for spec in "${specs[@]}"; do
WIN16_WING=$wing
name="$spec (wing=$wing)"
if [ "$spec" = "$fullSpec" ]; then
settings=(JOEYLIB_FULLSCREEN=1)
# 4:3 on the whole 800x600 screen.
w=$desktopWidth
h=$desktopHeight
elif [[ "$spec" =~ ^([0-9]+)(:square)?$ ]]; then
scale=${BASH_REMATCH[1]}
w=$((stageWidth * scale))
if [ -n "${BASH_REMATCH[2]}" ]; then
settings=(JOEYLIB_SCALE="$scale" JOEYLIB_ASPECT=square)
h=$((stageHeight * scale))
else
settings=(JOEYLIB_SCALE="$scale")
h=$((w * 3 / 4))
fi
else
echo "$label: bad spec \"$spec\" (SCALE[:square] or $fullSpec)" >&2
exit 2
fi
want=$((stagePixels + w * h))
if [ $((w % stageWidth)) -eq 0 ] && [ $((h % stageHeight)) -eq 0 ]; then
want=$((want + w * h))
fi
win16Stop
[ -n "$work" ] && rm -rf "$work"
work=$(mktemp -d -t joeylib-win16-display.XXXXXX)
rm -f "$folder/JOEYLOG.TXT" "$folder/joeylog.txt"
win16Stage "$work" "$folder" "$program"
win16Start "$work" "${settings[@]}"
row=""
layout=""
for ((waited = 0; waited < runSeconds; waited++)); do
log=$(win16Log "$folder")
if [ -n "$log" ] && grep -q "$doneLine" "$log"; then
row=$(grep -F "$probeLine" "$log" | tr -d '\r' | tail -1)
layout=$(grep -F "$layoutLine" "$log" | tr -d '\r' | tail -1)
break
fi
joeyAlive "$WIN16_GUARD" || break
sleep 1
done
if [ -z "$row" ]; then
fail "$name" "no \"$probeLine\" line within ${runSeconds} s"
continue
fi
extra=$(printf '%s\n' "$layout" | sed -n 's/.*extra=\([0-9]*\).*/\1/p')
want=$((want + ${extra:-0}))
# The identity checks cover every window pixel and at least one palette.
if [[ "$layout" == *identity=1* ]] && [ "${extra:-0}" -lt $((w * h + 16)) ]; then
fail "$name" "the identity layout's checks compared only ${extra:-0}"
continue
fi
counts=${row#*"$probeLine" }
echo "$label: $spec (${w}x${h}, ${layout#*"$layoutLine" }): $counts"
if [[ "$layout" != *"wing=$wing "* ]]; then
fail "$name" "the probe did not draw with wing=$wing"
continue
fi
# Without WinG, the identity layout on this 8-bit desktop draws through
# device bitmaps.
if [ "$wing" = 0 ] && [[ "$layout" == *identity=1* ]] && [[ "$layout" != *"ddb=1 "* ]]; then
fail "$name" "the probe did not draw through device bitmaps"
continue
fi
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 "$name" "pixels differ: $bad"
elif [ "$compared" != "$want" ]; then
fail "$name" "compared $compared, want $want (is the window ${w}x${h}?)"
else
passed=$((passed + 1))
fi
done
done
if [ -n "$fails" ]; then
echo "$label: FAIL - $fails"
exit 1
fi
echo "$label: PASS ($passed runs, ${#specs[@]} window sizes with and without WinG as installed: every pixel shown matches the stage after every present)"