#!/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 # colour of the palettes in use against the system palette, which is where # an animated colour 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)"