- commit
- e41f0d44a2187327a06d1ab694f4186a48df3ca8
- parent
- 9ade966c0d7e07b9a6aef5ce004ab67136977939
- author
- Dami <dami.etoile@gmail.com>
| M | docs/ | 5 | +- |
| M | docs/ | 22 | +++- |
| M | scripts/ | 217 | ++++++++++++++++++++++++++- |
| A | scripts/ | 239 | ++++++++++++++++++++++++++++++ |
@@ -1563,7 +1563,10 @@ property to return, then rerun the pointer and feedback smoke without replaying
15631563 the redeemed invitation. Both runs must pass, the Sigil PID must remain15641564 unchanged, and the host log must contain one `Gamescope Xwayland pointer15651565 feedback reconnected` event per restart. The packaged hardware UAT performs1566-this sequence after its fixed-mode session checks.1566+this sequence after its fixed-mode session checks. That runner independently1567+enumerates `amdgpu` render nodes and matches the exact GstVA H.264 factory by1568+its inspected `device-path`; it never assumes `renderD128` is the AMD device or1569+that the matching factory is named `vah264enc`.15671570 15681571 For a deterministic pre-demo gamepad proof, leave `evtest "$gamepad_node"`15691572 running on the host and run this from the client checkout:@@ -42,4 +42,24 @@ host, copy the runner to that host, then execute there:
4242 ./run-bazzite-hardware-uat.sh UAT_ROOT FULL_COMMIT WORKFLOW_RUN_ID4343 ```4444 45-The runner rejects reused output directories and concurrent hardware runs.45+If more than one exact AMD render-node/factory pair satisfies the complete UAT46+contract, discovery fails closed and prints the eligible pairs. Select one pair47+explicitly and rerun:48+49+```sh50+./run-bazzite-hardware-uat.sh UAT_ROOT FULL_COMMIT WORKFLOW_RUN_ID \51+ --render-node /dev/dri/renderD129 \52+ --va-encoder varenderD129h264enc53+```54+55+The two override options are inseparable, and the requested pair must pass the56+same device, driver, factory binding, property, CBR, and CQP checks as automatic57+selection. The runner rejects reused output directories and concurrent hardware58+runs.59+Before generating its isolated configs, it enumerates DRM render nodes through60+sysfs, considers only nodes backed by `amdgpu`, and matches each accessible node61+to the exact dynamically registered GstVA H.264 factory whose read-only62+`device-path` names that node. The chosen factory must advertise both CBR (for63+the in-process fixed/native legs) and CQP (for the external compatibility leg).64+The gate therefore does not assume either `/dev/dri/renderD128` or the generic65+`vah264enc` factory. The selected pair is recorded in `summary.env`.@@ -2,14 +2,190 @@
22 33 set -euo pipefail44 5-if [[ $# -ne 3 ]]; then6- echo "usage: $0 UAT_ROOT UAT_COMMIT WORKFLOW_RUN_ID" >&25+gst_property_block_contains() {6+ local property="$1"7+ local needle="$2"8+9+ awk -v property="$property" -v needle="$needle" '10+ $0 ~ ("^ " property "[[:space:]]+:") {11+ inside = 112+ }13+ inside && index($0, needle) {14+ found = 115+ }16+ inside && $0 !~ ("^ " property "[[:space:]]+:") \17+ && $0 ~ /^ [^[:space:]].*[[:space:]]+:/ {18+ exit19+ }20+ END { exit !found }21+ '22+}23+24+gst_property_block_is_writable() {25+ local property="$1"26+27+ awk -v property="$property" '28+ $0 ~ ("^ " property "[[:space:]]+:") {29+ inside = 130+ }31+ inside && index(tolower($0), "writable") {32+ found = 133+ }34+ inside && $0 !~ ("^ " property "[[:space:]]+:") \35+ && $0 ~ /^ [^[:space:]].*[[:space:]]+:/ {36+ exit37+ }38+ END { exit !found }39+ '40+}41+42+gstva_factory_supports_uat() {43+ local inspection="$1"44+ local property45+46+ gst_property_block_contains rate-control cbr <<<"$inspection" || return 147+ gst_property_block_contains rate-control cqp <<<"$inspection" || return 148+ for property in \49+ aud b-frames key-int-max rate-control ref-frames target-usage bitrate qpi qpp50+ do51+ gst_property_block_is_writable "$property" <<<"$inspection" || return 152+ done53+}54+55+select_amd_gstva_h264_encoder() {56+ local gst_inspect_path="$1"57+ local sysfs_root="${2:-/sys/class/drm}"58+ local device_root="${3:-/dev/dri}"59+ local require_character="${4:-true}"60+ local override_node="${5:-}"61+ local override_factory="${6:-}"62+ local factory63+ local factories64+ local inspection65+ local node_name66+ local sysfs_node67+ local driver68+ local candidate69+ local pair70+ local candidate_count=071+72+ render_node=''73+ va_encoder=''74+ va_candidates=''75+ factories="$(76+ LC_ALL=C "$gst_inspect_path" 2>/dev/null | awk '77+ $2 ~ /^va(renderD[0-9]+)?h264(lp)?enc:$/ {78+ sub(/:$/, "", $2)79+ print $280+ }81+ ' | sort -u82+ )" || return 183+84+ for sysfs_node in "$sysfs_root"/renderD*; do85+ [[ -e "$sysfs_node/device/driver" ]] || continue86+ node_name="$(basename "$sysfs_node")"87+ [[ "$node_name" =~ ^renderD[0-9]+$ ]] || continue88+ driver="$(basename "$(readlink -f "$sysfs_node/device/driver")")" || continue89+ [[ "$driver" == amdgpu ]] || continue90+ candidate="$device_root/$node_name"91+ [[ -e "$candidate" && ! -L "$candidate" && -r "$candidate" && -w "$candidate" ]] \92+ || continue93+ if [[ "$require_character" == true && ! -c "$candidate" ]]; then94+ continue95+ fi96+97+ while IFS= read -r factory; do98+ [[ -n "$factory" ]] || continue99+ if ! inspection="$(LC_ALL=C "$gst_inspect_path" "$factory" 2>/dev/null)"; then100+ continue101+ fi102+ gst_property_block_contains device-path "Default: \"$candidate\"" \103+ <<<"$inspection" || continue104+ gstva_factory_supports_uat "$inspection" || continue105+ pair="$candidate $factory"106+ if [[ -n "$va_candidates" ]]; then107+ va_candidates="$va_candidates108+$pair"109+ else110+ va_candidates="$pair"111+ fi112+ candidate_count=$((candidate_count + 1))113+ if [[ -n "$override_node" && "$candidate" == "$override_node" \114+ && "$factory" == "$override_factory" ]]; then115+ render_node="$candidate"116+ va_encoder="$factory"117+ elif [[ -z "$override_node" && "$candidate_count" -eq 1 ]]; then118+ render_node="$candidate"119+ va_encoder="$factory"120+ fi121+ done <<<"$factories"122+ done123+124+ if [[ -n "$override_node" ]]; then125+ [[ -n "$render_node" && -n "$va_encoder" ]]126+ return127+ fi128+ if [[ "$candidate_count" -eq 1 ]]; then129+ return 0130+ fi131+ render_node=''132+ va_encoder=''133+ [[ "$candidate_count" -eq 0 ]] && return 1134+ return 2135+}136+137+if [[ "${SIGIL_HARDWARE_UAT_SOURCE_ONLY:-}" == 1 ]]; then138+ if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then139+ return 0140+ fi141+ exit 0142+fi143+144+usage() {145+ echo "usage: $0 UAT_ROOT UAT_COMMIT WORKFLOW_RUN_ID [--render-node PATH --va-encoder FACTORY]" >&2146+}147+148+if [[ $# -lt 3 ]]; then149+ usage7150 exit 648151 fi9152 10153 uat_root="$1"11154 uat_commit="$2"12155 workflow_run_id="$3"156+shift 3157+render_node_override=''158+va_encoder_override=''159+render_node_override_set=false160+va_encoder_override_set=false161+while [[ $# -gt 0 ]]; do162+ case "$1" in163+ --render-node)164+ [[ $# -ge 2 && "$render_node_override_set" == false && -n "$2" ]] \165+ || { usage; exit 64; }166+ render_node_override="$2"167+ render_node_override_set=true168+ shift 2169+ ;;170+ --va-encoder)171+ [[ $# -ge 2 && "$va_encoder_override_set" == false && -n "$2" ]] \172+ || { usage; exit 64; }173+ va_encoder_override="$2"174+ va_encoder_override_set=true175+ shift 2176+ ;;177+ *)178+ usage179+ exit 64180+ ;;181+ esac182+done183+if [[ "$render_node_override_set" == true || "$va_encoder_override_set" == true ]]; then184+ [[ "$render_node_override_set" == true && "$va_encoder_override_set" == true ]] || {185+ echo "--render-node and --va-encoder must be provided together" >&2186+ exit 64187+ }188+fi13189 short_commit="${uat_commit:0:12}"14190 15191 [[ "$uat_commit" =~ ^[0-9a-f]{40}$ ]] || {@@ -206,10 +382,36 @@ xprop="$(command -v xprop)"
206382 gst_launch="$(command -v gst-launch-1.0)"207383 gst_inspect="$(command -v gst-inspect-1.0)"208384 ffmpeg="$(command -v ffmpeg)"209-render_node=/dev/dri/renderD128210-va_encoder=vah264enc211-[[ -S "$XDG_RUNTIME_DIR/pipewire-0" && -r "$render_node" && -w "$render_node" ]]212-"$gst_inspect" "$va_encoder" >/dev/null385+[[ -S "$XDG_RUNTIME_DIR/pipewire-0" ]]386+selection_status=0387+select_amd_gstva_h264_encoder \388+ "$gst_inspect" /sys/class/drm /dev/dri true \389+ "$render_node_override" "$va_encoder_override" || selection_status=$?390+if [[ "$selection_status" -ne 0 ]]; then391+ if [[ -n "$render_node_override" ]]; then392+ echo "the requested render-node and VA-encoder pair is not eligible for this UAT" >&2393+ elif [[ "$selection_status" -eq 2 ]]; then394+ echo "multiple AMD GstVA H.264 encoder pairs are eligible; select one exact pair with --render-node and --va-encoder" >&2395+ else396+ echo "no accessible AMD render node has a GstVA H.264 factory satisfying the CBR and CQP UAT contract" >&2397+ fi398+ if [[ -n "$va_candidates" ]]; then399+ while IFS= read -r pair; do400+ printf 'eligible_pair=%s\n' "$pair" >&2401+ done <<<"$va_candidates"402+ fi403+ exit 1404+fi405+if [[ -n "$render_node_override" ]]; then406+ vaapi_selection_mode=explicit407+else408+ vaapi_selection_mode=automatic-unique409+fi410+{411+ echo "vaapi_render_node=$render_node"412+ echo "vaapi_encoder=$va_encoder"413+ echo "vaapi_selection_mode=$vaapi_selection_mode"414+} >"$private/vaapi-selection.env"213415 214416 cat >"$fixed_config" <<EOF215417 identity_path = "$host_identity"@@ -812,6 +1014,9 @@ fi
8121014 echo "fixed_observed_fps=$fixed_observed_fps"8131015 echo external_cqp_minimum_fps=558141016 echo "external_cqp_observed_fps=$external_cqp_observed_fps"1017+ echo "vaapi_render_node=$render_node"1018+ echo "vaapi_encoder=$va_encoder"1019+ echo "vaapi_selection_mode=$vaapi_selection_mode"8151020 echo cross_state_capture_contention=rejected8161021 echo gamescope_pointer_restart_cycles=28171022 echo gamescope_pointer_feedback_recovery=pass@@ -0,0 +1,239 @@
1+2+3+set -euo pipefail4+5+script_dir="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"6+runner="$script_dir/../run-bazzite-hardware-uat.sh"7+temp_parent="${TMPDIR:-/tmp}"8+temp_parent="${temp_parent%/}"9+temp_root="$(mktemp -d "$temp_parent/sigil-hardware-selection.XXXXXX")"10+11+cleanup() {12+ local status=$?13+ trap - EXIT INT TERM HUP14+ case "$temp_root" in15+ "$temp_parent"/sigil-hardware-selection.??????) rm -rf -- "$temp_root" ;;16+ esac17+ exit "$status"18+}19+trap cleanup EXIT INT TERM HUP20+21+export SIGIL_HARDWARE_UAT_SOURCE_ONLY=122+# shellcheck source=../run-bazzite-hardware-uat.sh23+# shellcheck disable=SC109124+source "$runner"25+render_node=''26+va_encoder=''27+va_candidates=''28+29+fail() {30+ printf 'FAIL: %s\n' "$1" >&231+ exit 132+}33+34+fixture="$temp_root/fixture"35+sysfs_root="$fixture/sys/class/drm"36+device_root="$fixture/dev/dri"37+drivers="$fixture/drivers"38+bin="$fixture/bin"39+factory_fixture="$fixture/factories.tsv"40+install -d -m 0700 \41+ "$sysfs_root" "$device_root" "$drivers/amdgpu" "$drivers/i915" "$bin"42+43+add_render_node() {44+ local name="$1"45+ local driver="$2"46+47+ install -d -m 0700 "$sysfs_root/$name/device"48+ ln -s "$drivers/$driver" "$sysfs_root/$name/device/driver"49+ install -m 0600 /dev/null "$device_root/$name"50+}51+52+reset_render_nodes() {53+ rm -rf -- "$sysfs_root"54+ rm -rf -- "$device_root"55+ install -d -m 0700 "$sysfs_root" "$device_root"56+}57+58+cat >"$bin/gst-inspect-1.0" <<'EOF'59+#!/usr/bin/env bash60+set -euo pipefail61+62+fixture="${SIGIL_TEST_FACTORY_FIXTURE:?}"63+if [[ $# -eq 0 ]]; then64+ awk -F '\t' '{ printf "va: %s: fixture encoder\n", $1 }' "$fixture"65+ exit 066+fi67+68+record="$(awk -F '\t' -v factory="$1" '$1 == factory { print; exit }' "$fixture")"69+[[ -n "$record" ]] || exit 170+IFS=$'\t' read -r factory device modes completeness <<<"$record"71+printf '%s\n' \72+ ' device-path : DRM render device' \73+ ' flags: readable' \74+ " String. Default: \"$device\"" \75+ ' rate-control : Rate control mode' \76+ ' flags: readable, writable'77+case ",$modes," in78+ *,cqp,*) printf '%s\n' ' (1): cqp' ;;79+esac80+case ",$modes," in81+ *,cbr,*) printf '%s\n' ' (2): cbr' ;;82+esac83+for property in aud b-frames key-int-max ref-frames target-usage bitrate qpi qpp; do84+ [[ "$completeness" == "missing-$property" ]] && continue85+ printf ' %-20s: fixture property\n' "$property"86+ printf '%s\n' ' flags: readable, writable'87+done88+EOF89+chmod 0755 "$bin/gst-inspect-1.0"90+export SIGIL_TEST_FACTORY_FIXTURE="$factory_fixture"91+92+select_fixture() {93+ select_amd_gstva_h264_encoder \94+ "$bin/gst-inspect-1.0" "$sysfs_root" "$device_root" false \95+ "${1:-}" "${2:-}"96+}97+98+reset_render_nodes99+add_render_node renderD128 i915100+add_render_node renderD129 amdgpu101+printf '%s\t%s\t%s\t%s\n' \102+ vah264enc "$device_root/renderD128" cqp,cbr complete \103+ varenderD129h264lpenc "$device_root/renderD129" cqp complete \104+ varenderD129h264enc "$device_root/renderD129" cqp,cbr complete \105+ >"$factory_fixture"106+select_fixture || fail 'a matching non-primary AMD encoder was not selected'107+[[ "$render_node" == "$device_root/renderD129" ]] || \108+ fail 'the Intel renderD128 node was selected instead of the AMD node'109+[[ "$va_encoder" == varenderD129h264enc ]] || \110+ fail 'the exact CBR+CQP per-device factory was not selected'111+112+reset_render_nodes113+add_render_node renderD130 amdgpu114+printf '%s\t%s\t%s\t%s\n' \115+ vah264enc "$device_root/renderD130" cqp,cbr complete \116+ >"$factory_fixture"117+select_fixture || fail 'a generic factory backed by renderD130 was not selected'118+[[ "$render_node" == "$device_root/renderD130" && "$va_encoder" == vah264enc ]] || \119+ fail 'selection retained a renderD128 or per-device factory assumption'120+121+reset_render_nodes122+add_render_node renderD128 amdgpu123+add_render_node renderD129 amdgpu124+printf '%s\t%s\t%s\t%s\n' \125+ vah264enc "$device_root/renderD128" cqp,cbr complete \126+ varenderD129h264enc "$device_root/renderD129" cqp,cbr complete \127+ >"$factory_fixture"128+selection_status=0129+select_fixture || selection_status=$?130+[[ "$selection_status" -eq 2 ]] || fail 'two viable AMD pairs were not ambiguous'131+[[ -z "$render_node" && -z "$va_encoder" ]] || \132+ fail 'ambiguous discovery retained a silent first selection'133+grep -Fxq "$device_root/renderD128 vah264enc" <<<"$va_candidates" || \134+ fail 'the first ambiguous pair was not reported'135+grep -Fxq "$device_root/renderD129 varenderD129h264enc" <<<"$va_candidates" || \136+ fail 'the second ambiguous pair was not reported'137+138+select_fixture "$device_root/renderD129" varenderD129h264enc || \139+ fail 'a valid explicit pair was rejected'140+[[ "$render_node" == "$device_root/renderD129" \141+ && "$va_encoder" == varenderD129h264enc ]] || \142+ fail 'the explicit pair did not win ambiguous discovery'143+if select_fixture "$device_root/renderD129" vah264enc; then144+ fail 'a mismatched explicit node/factory pair was accepted'145+fi146+147+reset_render_nodes148+add_render_node renderD130 amdgpu149+printf '%s\t%s\t%s\t%s\n' \150+ vah264enc "$device_root/renderD129" cqp,cbr complete \151+ >"$factory_fixture"152+if select_fixture; then153+ fail 'a factory whose device-path mismatched the AMD node was accepted'154+fi155+156+for modes in cqp cbr; do157+ printf '%s\t%s\t%s\t%s\n' \158+ vah264enc "$device_root/renderD130" "$modes" complete \159+ >"$factory_fixture"160+ if select_fixture; then161+ fail "a factory advertising only $modes was accepted"162+ fi163+done164+printf '%s\t%s\t%s\t%s\n' \165+ vah264enc "$device_root/renderD130" cqp,cbr missing-bitrate \166+ >"$factory_fixture"167+if select_fixture; then168+ fail 'a factory missing a required writable property was accepted'169+fi170+171+printf '%s\t%s\t%s\t%s\n' \172+ x264enc "$device_root/renderD130" cqp,cbr complete \173+ vah264enc-malformed "$device_root/renderD130" cqp,cbr complete \174+ >"$factory_fixture"175+if select_fixture; then176+ fail 'malformed or software factory names were accepted'177+fi178+179+printf '%s\t%s\t%s\t%s\n' \180+ vah264enc "$device_root/renderD130" cqp,cbr complete \181+ vah264enc "$device_root/renderD130" cqp,cbr complete \182+ >"$factory_fixture"183+select_fixture || fail 'duplicate listing of one factory became ambiguous'184+[[ "$va_encoder" == vah264enc ]] || fail 'duplicate factory selection was unstable'185+186+rm -f -- "$device_root/renderD130"187+ln -s "$temp_root/missing-render-node" "$device_root/renderD130"188+if select_fixture; then189+ fail 'a symlink render node was accepted'190+fi191+rm -f -- "$device_root/renderD130"192+install -m 0600 /dev/null "$device_root/renderD130"193+if select_amd_gstva_h264_encoder \194+ "$bin/gst-inspect-1.0" "$sysfs_root" "$device_root" true '' ''195+then196+ fail 'a regular file was accepted as a production DRM character device'197+fi198+[[ -z "$render_node" && -z "$va_encoder" ]] || \199+ fail 'failed discovery retained stale selection state'200+201+encoder_config_line="vaapi_encoder = \"\$va_encoder\""202+render_node_config_line="vaapi_render_node = \"\$render_node\""203+[[ "$(grep -Fc "$encoder_config_line" "$runner")" -eq 3 ]] || \204+ fail 'not every generated UAT config uses the selected factory'205+[[ "$(grep -Fc "$render_node_config_line" "$runner")" -eq 3 ]] || \206+ fail 'not every generated UAT config uses the selected render node'207+if grep -Eq 'render_node=/dev/dri/renderD128|va_encoder=vah264enc' "$runner"; then208+ fail 'the hardware runner still pins the original render node or factory'209+fi210+211+fake_commit=0123456789abcdef0123456789abcdef01234567212+parser_error="$temp_root/parser.error"213+parser_status=0214+SIGIL_HARDWARE_UAT_SOURCE_ONLY=0 bash "$runner" /invalid "$fake_commit" 1 \215+ --render-node /dev/dri/renderD129 > /dev/null 2>"$parser_error" \216+ || parser_status=$?217+[[ "$parser_status" -eq 64 ]] || fail 'a partial override did not fail as usage error'218+grep -Fxq -- '--render-node and --va-encoder must be provided together' \219+ "$parser_error" || fail 'a partial override did not explain the paired requirement'220+221+parser_status=0222+SIGIL_HARDWARE_UAT_SOURCE_ONLY=0 bash "$runner" /invalid "$fake_commit" 1 \223+ --unknown value > /dev/null 2>"$parser_error" || parser_status=$?224+[[ "$parser_status" -eq 64 ]] || fail 'an unknown override did not fail as usage error'225+grep -Fq 'usage:' "$parser_error" || fail 'an unknown override did not print usage'226+227+parser_status=0228+SIGIL_HARDWARE_UAT_SOURCE_ONLY=0 bash "$runner" /invalid "$fake_commit" 1 \229+ --render-node /dev/dri/renderD128 --render-node /dev/dri/renderD129 \230+ --va-encoder vah264enc > /dev/null 2>"$parser_error" || parser_status=$?231+[[ "$parser_status" -eq 64 ]] || fail 'a duplicate override was accepted'232+233+parser_status=0234+SIGIL_HARDWARE_UAT_SOURCE_ONLY=0 bash "$runner" /invalid "$fake_commit" 1 \235+ --render-node '' --va-encoder vah264enc \236+ > /dev/null 2>"$parser_error" || parser_status=$?237+[[ "$parser_status" -eq 64 ]] || fail 'an empty override value was accepted'238+239+printf 'bazzite_hardware_uat_selection_tests=ok\n'