#!/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-be-display.sh - Display parity gate for a Be API port (haiku, # haiku32, beos): 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 Be backend copies # into its bitmap, 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 builds it, into build//probe) ends with P13, the # battery the other display gates run, which after every step asks the # backend (hostBeProbeDisplayMismatch in src/hosted/be/beBackend.cpp) how many # pixels differ: the frame's against the stage, the bitmap's against the # frame, and the window as the shows left it against the window fully # repainted, both read back from the screen (BScreen::ReadBitmap). Every # count must be 0, and every pixel must have been compared: 64000 twice, # plus the window's (the size the probe logs). # # One VM boot (scripts/lib/beGate.sh) runs UBERPROB once a spec, with # JOEYLIB_SCALE / JOEYLIB_ASPECT / JOEYLIB_FULLSCREEN set as it asks. # # Usage: scripts/verify-be-display.sh [haiku|haiku32|beos] [SCALE[:square] | full]... # (default haiku; specs 1:square 2:square 3 full) # Requires: QEMU and the port's VM (install.sh install emulator:); # build//probe/UBERPROB (make ). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/beGate.sh" port=${1:-haiku} shift || true label="verify-be-display ($port)" beNeed "$port" program=$repo/build/$port/probe/UBERPROB probeLine="UBER-PROBE: beDisplayMismatch" sizeLine="UBER-PROBE: beWindow" doneLine="UBER: press any key to exit" stagePixels=$((320 * 200)) fullSpec=full bootSeconds=120 runSeconds=120 # one probe run, start to done line defaults=(1:square 2:square 3 "$fullSpec") specs=("$@") [ ${#specs[@]} -gt 0 ] || specs=("${defaults[@]}") [ -x "$program" ] || { echo "$label: the probe build is missing; run: make $port" >&2; exit 2; } work=$(mktemp -d -t joeylib-be-display.XXXXXX) cleanup() { beStop rm -rf "$work" } trap cleanup EXIT # The job: each spec's run in a subshell of its own (its folder and # settings stay there), its log kept as log.txt. mkdir -p "$work/job/UBERPROB" cp "$program" "$work/job/UBERPROB/UBERPROB" : > "$work/job/job.sh" n=0 for spec in "${specs[@]}"; do if [ "$spec" = "$fullSpec" ]; then settings=(JOEYLIB_FULLSCREEN=1) elif [[ "$spec" =~ ^([0-9]+)(:square)?$ ]]; then settings=(JOEYLIB_SCALE="${BASH_REMATCH[1]}") [ -n "${BASH_REMATCH[2]}" ] && settings+=(JOEYLIB_ASPECT=square) else echo "$label: bad spec \"$spec\" (SCALE[:square] or $fullSpec)" >&2 exit 2 fi { printf '(\n' printf 'rm -f UBERPROB/joeylog.txt\n' beJobScript UBERPROB UBERPROB "$doneLine" "$runSeconds" "${settings[@]}" printf ')\n' printf 'cp UBERPROB/joeylog.txt log%s.txt\n' "$n" } >> "$work/job/job.sh" n=$((n + 1)) done beJobDisk "$work/job.img" "$work/job" beStart "$work" "$work/job.img" if ! beWaitJob "$work" "$bootSeconds"; then echo "$label: FAIL - the VM did not start the job within ${bootSeconds} s" >&2 exit 1 fi if ! beWaitExit "$work" "$((runSeconds * ${#specs[@]} + 60))"; then echo "$label: FAIL - the runs did not finish" >&2 exit 1 fi 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" } n=0 for spec in "${specs[@]}"; do log=$work/log$n.txt n=$((n + 1)) beJobGet "$work/job.img" "log$((n - 1)).txt" "$log" || true row=$(grep -F "$probeLine" "$log" 2> /dev/null | tr -d '\r' | tail -1) size=$(grep -F "$sizeLine" "$log" 2> /dev/null | tr -d '\r' | tail -1) if [ -z "$row" ] || [ -z "$size" ]; then fail "$spec" "no \"$probeLine\" line" continue fi size=${size#*"$sizeLine" } w=${size%x*} h=${size#*x} want=$((2 * stagePixels + w * h)) 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" 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)"