diff --git a/CHANGELOG.md b/CHANGELOG.md index 09a6506..6abfec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ this file as both a release log and a lightweight development progress record. ### Added +- Phase35 native-vs-modern DisplayEngine visual validation foundation for OVMF + X64: `Scripts/capture-displayengine-ovmf-x64.sh` creates separated native and + modern overlay/build/capture artifact paths under a safe TMPDIR default, + `Tests/Manual/DisplayEngineOvmfX64Visual.md` documents evidence levels and + limitations, and smoke checks enforce the script/doc contract without claiming + visual verification. - Phase34 DisplayEngine row rendering hardening: statement row GOP surfaces now classify highlighted/selected, disabled/locked, read-only, changed, invalid, modal, and action/text affordance state through the private FormModel helpers, diff --git a/Docs/ProductizationValidationMatrix.md b/Docs/ProductizationValidationMatrix.md index 13a77eb..518eb85 100644 --- a/Docs/ProductizationValidationMatrix.md +++ b/Docs/ProductizationValidationMatrix.md @@ -28,6 +28,7 @@ The validation terms below describe current evidence only: - `Script`: a repository script exists and is checked for syntax/metadata. - `Manual`: local maintainer validation path is documented, but not CI-gated. - `Captured`: screenshot/screendump evidence exists for a path. +- `Visual reviewed`: captured native-vs-modern screenshots were inspected by a maintainer; do not use this term for static smoke, build-only, or QEMU boot-only results. - `Build/script validation`: the script/overlay path is validated without claiming graphical runtime evidence. - `Planned`: documented target or behavior only; do not describe it as validated. @@ -35,13 +36,19 @@ The validation terms below describe current evidence only: | XArch target | Concrete edk2 ARCH | Platform path | Primary scripts | Current maturity evidence | Productization validation notes | | --- | --- | --- | --- | --- | --- | -| X64 / OVMF X64 | `X64` | `OvmfPkg/OvmfPkgX64` | `Scripts/build-ovmf-x64.sh`, `Scripts/run-ovmf-x64.sh`, `Scripts/capture-ovmf-x64.sh` | Manual OVMF build/run/capture path; smoke overlay generation; local/manual App validation. | Evidence supports target metadata, native/modern DisplayEngine overlay separation, and local screenshot capture path. | +| X64 / OVMF X64 | `X64` | `OvmfPkg/OvmfPkgX64` | `Scripts/build-ovmf-x64.sh`, `Scripts/run-ovmf-x64.sh`, `Scripts/capture-ovmf-x64.sh`, `Scripts/capture-displayengine-ovmf-x64.sh` | Manual OVMF build/run/capture path; smoke overlay generation; local/manual App validation; Phase35 native-vs-modern DisplayEngine evidence path pending visual review. | Evidence supports target metadata, native/modern DisplayEngine overlay separation, and local screenshot capture path. The DisplayEngine A/B helper defaults to `${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64` and only becomes screenshot evidence after `--mode capture` produces artifacts. | | AARCH64 / ArmVirtQemu | `AARCH64` | `ArmVirtPkg/ArmVirtQemu` | `Scripts/build-armvirt.sh`, `Scripts/run-armvirt.sh`, `Scripts/capture-armvirt.sh`, `Scripts/build-modern-app.sh` | Captured ArmVirt before/after evidence; active build/run path; smoke overlay generation. | Primary compatibility capture path for native UiApp/FormBrowser plus ModernDisplayEngine. | | LOONGARCH64 / LoongArchVirtQemu | `LOONGARCH64` | `OvmfPkg/LoongArchVirt/LoongArchVirtQemu` | `Scripts/build-loongarchvirt.sh`, `Scripts/run-loongarchvirt.sh` | Active build/run script path; smoke overlay generation. | Evidence covers generated overlays and documented manual run path; external cross toolchain remains product-team responsibility. | | RISCV64 / RiscVVirtQemu | `RISCV64` | `OvmfPkg/RiscVVirt/RiscVVirtQemu` | `Scripts/build-riscvvirt.sh` | Build/script validation; smoke overlay generation. | RISCV64 remains Build/script validation in Phase30; graphical QEMU helper and captured UI evidence are not claimed. | `Scripts/xarch-validate.sh --all --mode dry-run --format json` is the fast target metadata smoke companion. In Phase30 the smoke gate asserts four target `PASS` results and preserves the RISCV64 `Build/script validation` maturity wording. +## Phase35 DisplayEngine Visual Evidence Path + +`Tests/Manual/DisplayEngineOvmfX64Visual.md` documents the OVMF X64 native-vs-modern DisplayEngine visual workflow. `Scripts/capture-displayengine-ovmf-x64.sh` drives the existing OVMF overlay generator with `MODERN_SETUP_DISPLAY_ENGINE=native` and `MODERN_SETUP_DISPLAY_ENGINE=modern`, keeps artifacts separated under `overlays/native`, `overlays/modern`, `firmware/native`, `firmware/modern`, and optional `native`/`modern` capture directories, and preserves upstream edk2 platform files by writing overlays only under `Build/ModernSetupPkgOverlay`. The helper does not inspect pixels and does not mark visual equivalence as verified. + +Current Phase35 status in this matrix is `Script`/`Manual` foundation only. Static smoke can check that the helper and manual workflow exist; `--mode generate-only` can check overlay snapshots; `--mode build` can check firmware FD snapshots; only `--mode capture` with successful QEMU `screendump` output creates visual screenshot evidence, and the helper does not inspect pixels or mark visual equivalence as verified. + ## Product Class Validation Matrix | Product class | Evidence-backed App role | Native owner / boundary | Current validation evidence | diff --git a/Docs/ProductizationValidationMatrix.zh-CN.md b/Docs/ProductizationValidationMatrix.zh-CN.md index a95e651..6eb4e01 100644 --- a/Docs/ProductizationValidationMatrix.zh-CN.md +++ b/Docs/ProductizationValidationMatrix.zh-CN.md @@ -28,6 +28,7 @@ XArch 是 ModernSetupPkg 的跨架构验证/产品化术语。XArch 不会替代 - `Script`:仓库脚本存在,并被语法/元数据检查覆盖。 - `Manual`:本地维护者验证路径已有文档,但不是 CI gate。 - `Captured`:相关路径有截图或 screendump 证据。 +- `Visual reviewed`:维护者已检查 native-vs-modern 截图;不要将此术语用于 static smoke、仅构建或仅 QEMU 启动结果。 - `Build/script validation`:脚本或 overlay 路径已验证,但不声明图形运行证据。 - `Planned`:仅为规划或已记录目标,不应描述成已验证。 @@ -35,13 +36,19 @@ XArch 是 ModernSetupPkg 的跨架构验证/产品化术语。XArch 不会替代 | XArch 目标 | 具体 edk2 ARCH | 平台路径 | 主要脚本 | 当前成熟度证据 | 产品化验证说明 | | --- | --- | --- | --- | --- | --- | -| X64 / OVMF X64 | `X64` | `OvmfPkg/OvmfPkgX64` | `Scripts/build-ovmf-x64.sh`, `Scripts/run-ovmf-x64.sh`, `Scripts/capture-ovmf-x64.sh` | Manual OVMF 构建/运行/捕获路径;smoke overlay generation;本地/手动 App 验证。 | 证据覆盖目标元数据、native/modern DisplayEngine overlay 分离和本地截图捕获路径。 | +| X64 / OVMF X64 | `X64` | `OvmfPkg/OvmfPkgX64` | `Scripts/build-ovmf-x64.sh`, `Scripts/run-ovmf-x64.sh`, `Scripts/capture-ovmf-x64.sh`, `Scripts/capture-displayengine-ovmf-x64.sh` | Manual OVMF 构建/运行/捕获路径;smoke overlay generation;本地/手动 App 验证;Phase35 native-vs-modern DisplayEngine 证据路径待 visual review。 | 证据覆盖目标元数据、native/modern DisplayEngine overlay 分离和本地截图捕获路径。DisplayEngine A/B helper 默认输出到 `${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64`,只有 `--mode capture` 产出 artifact 后才属于截图证据。 | | AARCH64 / ArmVirtQemu | `AARCH64` | `ArmVirtPkg/ArmVirtQemu` | `Scripts/build-armvirt.sh`, `Scripts/run-armvirt.sh`, `Scripts/capture-armvirt.sh`, `Scripts/build-modern-app.sh` | Captured ArmVirt before/after 证据;active 构建/运行路径;smoke overlay generation。 | native UiApp/FormBrowser 加 ModernDisplayEngine 的主要兼容性捕获路径。 | | LOONGARCH64 / LoongArchVirtQemu | `LOONGARCH64` | `OvmfPkg/LoongArchVirt/LoongArchVirtQemu` | `Scripts/build-loongarchvirt.sh`, `Scripts/run-loongarchvirt.sh` | Active 构建/运行脚本路径;smoke overlay generation。 | 证据覆盖生成 overlay 和已记录的手动运行路径;外部交叉工具链仍由产品团队负责。 | | RISCV64 / RiscVVirtQemu | `RISCV64` | `OvmfPkg/RiscVVirt/RiscVVirtQemu` | `Scripts/build-riscvvirt.sh` | Build/script validation;smoke overlay generation。 | Phase30 中 RISCV64 仍保持 Build/script validation;不声明图形 QEMU helper 或捕获 UI 证据。 | `Scripts/xarch-validate.sh --all --mode dry-run --format json` 是快速目标元数据 smoke 辅助检查。Phase30 smoke gate 会断言四个目标均为 `PASS`,并保持 RISCV64 的 `Build/script validation` 成熟度用语。 +## Phase35 DisplayEngine 视觉证据路径 + +`Tests/Manual/DisplayEngineOvmfX64Visual.md` 记录 OVMF X64 native-vs-modern DisplayEngine 视觉工作流。`Scripts/capture-displayengine-ovmf-x64.sh` 使用 `MODERN_SETUP_DISPLAY_ENGINE=native` 和 `MODERN_SETUP_DISPLAY_ENGINE=modern` 两次驱动既有 OVMF overlay 生成器,将 artifact 分离到 `overlays/native`、`overlays/modern`、`firmware/native`、`firmware/modern` 以及可选的 `native`/`modern` capture 目录,并只在 `Build/ModernSetupPkgOverlay` 下写 overlay,保持 upstream edk2 平台文件不被修改。 + +本矩阵中的 Phase35 当前状态仅为 `Script`/`Manual` foundation。Static smoke 可检查 helper 和手动工作流存在;`--mode generate-only` 可检查 overlay snapshot;`--mode build` 可检查 firmware FD snapshot;只有 `--mode capture` 成功产出 QEMU `screendump` 后才形成视觉截图证据,并且该 helper 不检查像素,也不会将视觉等价标记为 verified。 + ## 产品类别验证矩阵 | 产品类别 | 有证据支持的 App 角色 | 原生 owner / 边界 | 当前验证证据 | diff --git a/Scripts/capture-displayengine-ovmf-x64.sh b/Scripts/capture-displayengine-ovmf-x64.sh new file mode 100755 index 0000000..949ad24 --- /dev/null +++ b/Scripts/capture-displayengine-ovmf-x64.sh @@ -0,0 +1,212 @@ +#!/usr/bin/env bash +# Copyright (c) 2026, MarsDoge. All rights reserved.
+# Author: MarsDoge (Dongyan Qian) +# Open source: https://github.com/MarsDoge/ModernSetupPkg +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +set -euo pipefail + +PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +# shellcheck disable=SC1091 +source "${PKG_DIR}/Scripts/edk2-workspace.sh" +WORKSPACE="$(DetectWorkspace)" +TARGET="${TARGET:-DEBUG}" +TOOL_CHAIN_TAG="${TOOL_CHAIN_TAG:-GCC}" +MODE="${MODE:-dry-run}" +BOOT_APP="${BOOT_APP:-0}" +BOOT_WAIT_SECONDS="${BOOT_WAIT_SECONDS:-12}" +SENDKEY_SEQUENCE="${SENDKEY_SEQUENCE:-esc,ret}" +CAPTURE_OUT_DIR="${CAPTURE_OUT_DIR:-${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64}" +CAPTURE_WORK_DIR="${CAPTURE_WORK_DIR:-${WORKSPACE}/Build/ModernSetupPkgCapture/DisplayEngineOvmfX64}" +BUILD_SCRIPT="${PKG_DIR}/Scripts/build-ovmf-x64.sh" +CAPTURE_SCRIPT="${PKG_DIR}/Scripts/capture-ovmf-x64.sh" + +usage() { + cat <<'USAGE' +Usage: Scripts/capture-displayengine-ovmf-x64.sh [--mode dry-run|generate-only|build|capture] + +Create an OVMF X64 native-vs-modern DisplayEngine evidence directory without +modifying upstream edk2 platform files. The helper drives the existing OVMF +overlay generator twice, once with MODERN_SETUP_DISPLAY_ENGINE=native and once +with MODERN_SETUP_DISPLAY_ENGINE=modern. + +Modes: + dry-run Print the planned artifact paths and commands only. Default. + generate-only Generate and copy native/modern overlay DSC/FDF files only. + build Build each variant and copy OVMF_CODE.fd/OVMF_VARS.fd into the + evidence directory for stable later capture. + capture Build each variant, then invoke Scripts/capture-ovmf-x64.sh for + QEMU screendumps in native/ and modern/ subdirectories. + +Important environment overrides: + WORKSPACE edk2 workspace. Auto-detected like other scripts. + TARGET, TOOL_CHAIN_TAG, JOBS, MODERN_SETUP_THEME + CAPTURE_OUT_DIR default: ${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64 + CAPTURE_WORK_DIR default: ${WORKSPACE}/Build/ModernSetupPkgCapture/DisplayEngineOvmfX64 + BOOT_APP default: 0, firmware/FormBrowser capture path + BOOT_WAIT_SECONDS default: 12 + SENDKEY_SEQUENCE default: esc,ret; comma-separated QEMU monitor sendkey list + +Limitations: capture mode collects QEMU screendumps and serial logs, but it does not inspect pixels and cannot guarantee host-independent navigation into a given +FormBrowser page. Treat generated files/builds/captures as separate evidence +levels in docs and reports. +USAGE +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --help|-h) + usage + exit 0 + ;; + --mode) + if [[ $# -lt 2 ]]; then + echo "Missing value for --mode" >&2 + exit 2 + fi + MODE="$2" + shift 2 + ;; + --mode=*) + MODE="${1#--mode=}" + shift + ;; + *) + echo "Unknown option '$1'" >&2 + usage >&2 + exit 2 + ;; + esac +done + +case "${MODE}" in + dry-run|generate-only|build|capture) ;; + *) + echo "Unsupported MODE/--mode '${MODE}'; use dry-run, generate-only, build, or capture" >&2 + exit 2 + ;; +esac + +if [[ -z "${CAPTURE_OUT_DIR}" ]]; then + echo "CAPTURE_OUT_DIR must not be empty" >&2 + exit 2 +fi + +variants=(native modern) + +locate_build_fd() { + local name="$1" + local found="" + shopt -s nullglob + for candidate in "${WORKSPACE}"/Build/OvmfX64*/"${TARGET}_${TOOL_CHAIN_TAG}"/FV/"${name}"; do + if [[ -z "${found}" || "${candidate}" -nt "${found}" ]]; then + found="${candidate}" + fi + done + shopt -u nullglob + if [[ -n "${found}" ]]; then + printf '%s\n' "${found}" + fi +} + +copy_overlay_artifacts() { + local variant="$1" + local variant_overlay_dir="${CAPTURE_OUT_DIR}/overlays/${variant}" + mkdir -p "${variant_overlay_dir}" + cp "${WORKSPACE}/Build/ModernSetupPkgOverlay/OvmfX64ModernSetup.dsc" "${variant_overlay_dir}/OvmfX64ModernSetup.dsc" + cp "${WORKSPACE}/Build/ModernSetupPkgOverlay/OvmfX64ModernSetup.fdf" "${variant_overlay_dir}/OvmfX64ModernSetup.fdf" +} + +copy_firmware_artifacts() { + local variant="$1" + local code_fd vars_fd variant_firmware_dir + code_fd="$(locate_build_fd OVMF_CODE.fd)" + vars_fd="$(locate_build_fd OVMF_VARS.fd)" + if [[ -z "${code_fd}" || -z "${vars_fd}" || ! -f "${code_fd}" || ! -f "${vars_fd}" ]]; then + echo "Unable to locate built OVMF_CODE.fd/OVMF_VARS.fd for ${variant} after build" >&2 + exit 1 + fi + variant_firmware_dir="${CAPTURE_OUT_DIR}/firmware/${variant}" + mkdir -p "${variant_firmware_dir}" + cp "${code_fd}" "${variant_firmware_dir}/OVMF_CODE.fd" + cp "${vars_fd}" "${variant_firmware_dir}/OVMF_VARS.fd" +} + +run_variant() { + local variant="$1" + local generate_only=1 + local variant_capture_dir + + case "${MODE}" in + dry-run) + echo "Would run: MODERN_SETUP_DISPLAY_ENGINE=${variant} GENERATE_ONLY=1 ${BUILD_SCRIPT}" + echo "Would write overlay artifacts: ${CAPTURE_OUT_DIR}/overlays/${variant}/" + if [[ "${variant}" == "modern" ]]; then + echo "Modern variant keeps product path: EDKII_FORM_DISPLAY_ENGINE_PROTOCOL -> ModernDisplayEngineDxe -> ModernUiCustomizedDisplayLib -> private FormModel -> renderer" + else + echo "Native variant keeps upstream MdeModulePkg DisplayEngineDxe/CustomizedDisplayLib" + fi + return 0 + ;; + generate-only) + generate_only=1 + ;; + build|capture) + generate_only=0 + ;; + esac + + MODERN_SETUP_DISPLAY_ENGINE="${variant}" GENERATE_ONLY="${generate_only}" "${BUILD_SCRIPT}" + copy_overlay_artifacts "${variant}" + + if [[ "${MODE}" == "build" || "${MODE}" == "capture" ]]; then + copy_firmware_artifacts "${variant}" + fi + + if [[ "${MODE}" == "capture" ]]; then + variant_capture_dir="${CAPTURE_OUT_DIR}/${variant}" + mkdir -p "${variant_capture_dir}" + OVMF_CODE="${CAPTURE_OUT_DIR}/firmware/${variant}/OVMF_CODE.fd" \ + OVMF_VARS="${CAPTURE_OUT_DIR}/firmware/${variant}/OVMF_VARS.fd" \ + BOOT_APP="${BOOT_APP}" \ + BOOT_WAIT_SECONDS="${BOOT_WAIT_SECONDS}" \ + SENDKEY_SEQUENCE="${SENDKEY_SEQUENCE}" \ + CAPTURE_OUT_DIR="${variant_capture_dir}" \ + CAPTURE_WORK_DIR="${CAPTURE_WORK_DIR}/${variant}" \ + CAPTURE_PREFIX="displayengine-ovmf-x64-${variant}" \ + "${CAPTURE_SCRIPT}" + fi +} + +mkdir -p "${CAPTURE_OUT_DIR}" "${CAPTURE_WORK_DIR}" + +cat > "${CAPTURE_OUT_DIR}/README.txt" < + +# DisplayEngine OVMF X64 Native-vs-Modern Visual Validation + +This is the Phase35 foundation for repeatable native-vs-modern FormBrowser +screenshot evidence on OVMF X64. It establishes a deterministic artifact layout +and workflow; it does not claim visual equivalence unless QEMU screendumps are +actually captured and reviewed. + +## Scope + +The comparison target is the DisplayEngine product path: + +`edk2 FormBrowser / EDKII_FORM_DISPLAY_ENGINE_PROTOCOL -> ModernDisplayEngineDxe -> ModernUiCustomizedDisplayLib -> private FormModel -> renderer` + +The native side uses upstream edk2 `DisplayEngineDxe` and upstream +`CustomizedDisplayLib`. The modern side replaces those overlay entries with +`ModernDisplayEngineDxe` and `ModernUiCustomizedDisplayLib` through the existing +OVMF overlay generator. + +This workflow intentionally does not promote `ModernUiHiiBridgeLib`, parse IFR +packages, implement ConfigAccess or varstore semantics, call `RouteConfig`, +`ExtractConfig`, `SetVariable`, `HiiSetBrowserData`, or directly invoke platform +ConfigAccess callbacks. + +## Evidence Levels + +Use precise evidence language when recording results: + +- Static smoke: script/doc existence and contract tokens only. +- Generate-only: native and modern overlay DSC/FDF snapshots were generated and + copied to the evidence directory. +- Build: each variant produced `OVMF_CODE.fd` and `OVMF_VARS.fd` snapshots. +- QEMU boot: QEMU launched far enough to run the capture helper. +- Visual screenshot: `screendump` PPM/PNG artifacts exist for both variants. +- Visual reviewed: a maintainer compared the intended FormBrowser surfaces. + +Do not mark the path `Verified` based only on static smoke, generate-only output, +build success, or a QEMU boot without screenshots. + +## Scripted Workflow + +Run from the ModernSetupPkg repository or an edk2 workspace containing +ModernSetupPkg: + +```sh +Scripts/capture-displayengine-ovmf-x64.sh --mode dry-run +``` + +Default output root: + +```text +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64 +``` + +The dry-run prints planned native and modern commands and writes a README in the +output root. No overlay, build, QEMU, or visual evidence is produced. + +Generate only the overlay snapshots: + +```sh +Scripts/capture-displayengine-ovmf-x64.sh --mode generate-only +``` + +Expected artifacts: + +```text +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/overlays/native/OvmfX64ModernSetup.dsc +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/overlays/native/OvmfX64ModernSetup.fdf +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/overlays/modern/OvmfX64ModernSetup.dsc +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/overlays/modern/OvmfX64ModernSetup.fdf +``` + +Build both firmware variants and copy stable FD snapshots: + +```sh +Scripts/capture-displayengine-ovmf-x64.sh --mode build +``` + +Expected additional artifacts: + +```text +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/firmware/native/OVMF_CODE.fd +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/firmware/native/OVMF_VARS.fd +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/firmware/modern/OVMF_CODE.fd +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/firmware/modern/OVMF_VARS.fd +``` + +Capture both variants with QEMU screendump: + +```sh +BOOT_WAIT_SECONDS=12 \ +Scripts/capture-displayengine-ovmf-x64.sh --mode capture +``` + +The default capture sequence sends `Esc,Enter` (`SENDKEY_SEQUENCE=esc,ret`) to +open the OVMF boot selector and enter the selected `EFI Firmware Setup` path. +If your host firmware timing differs, override `SENDKEY_SEQUENCE` and +`BOOT_WAIT_SECONDS` explicitly. + +Expected additional artifact directories: + +```text +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/native/ +${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64/modern/ +``` + +Each variant directory is populated by `Scripts/capture-ovmf-x64.sh`, normally +including PPM screendumps, optional PNG conversions, and serial logs under the +capture work directory. + +Set `CAPTURE_OUT_DIR=Assets/Screenshots/manual/displayengine-ovmf-x64` only when +intentionally collecting assets for commit. The default path stays under +`${TMPDIR:-/tmp}` to avoid accidental repository changes. + +## Native/Modern Selectors + +The helper invokes the existing build script with both selectors: + +```sh +MODERN_SETUP_DISPLAY_ENGINE=native GENERATE_ONLY=1 Scripts/build-ovmf-x64.sh +MODERN_SETUP_DISPLAY_ENGINE=modern GENERATE_ONLY=1 Scripts/build-ovmf-x64.sh +``` + +In build/capture mode it uses the same selectors with `GENERATE_ONLY=0` and then +copies the generated firmware files before switching variants, so later captures +use variant-distinct FD paths. + +## Manual Review Checklist + +For real visual review, capture the same FormBrowser surface in both variants and +record the exact `BOOT_WAIT_SECONDS`, `SENDKEY_SEQUENCE`, QEMU version, and host +GOP mode. Review at least: + +- FrontPage/native UiApp landing surface after `Esc` during BDS when reachable. +- Device Manager or Boot Manager page. +- One popup or dialog if navigation is reliable on the host. +- Serial logs for ASSERTs, exceptions, GOP failures, or unexpected boot denial. + +Expected result for Phase35 is not row polish. The useful outcome is a repeatable +artifact set that makes native and modern FormBrowser screenshots comparable. + +## Known Limitations + +The wrapper cannot guarantee host-independent automatic navigation into a +specific FormBrowser page. QEMU firmware timing, keyboard focus, boot policy, and +available OVMF setup entries can vary. `capture` mode produces screenshot +evidence only when QEMU and `screendump` complete; the script does not inspect +pixels, compare images, or assert visual equivalence. diff --git a/Tests/Smoke/smoke_validate.py b/Tests/Smoke/smoke_validate.py index 79125fb..196116f 100755 --- a/Tests/Smoke/smoke_validate.py +++ b/Tests/Smoke/smoke_validate.py @@ -57,6 +57,8 @@ ) OVMF_CAPTURE_HELPER = Path("Scripts") / "capture-ovmf-x64.sh" OVMF_CAPTURE_DOC = Path("Tests") / "Manual" / "OvmfX64Qemu.md" +DISPLAYENGINE_OVMF_VISUAL_HELPER = Path("Scripts") / "capture-displayengine-ovmf-x64.sh" +DISPLAYENGINE_OVMF_VISUAL_DOC = Path("Tests") / "Manual" / "DisplayEngineOvmfX64Visual.md" PROHIBITED_DEFAULT_OVERLAY_TOKENS = ( "ModernSetupApp", "ModernUiHiiBridgeLib", @@ -925,6 +927,96 @@ def check_ovmf_capture_helper_contract(root: Path) -> list[str]: return ["PASS OVMF X64 QEMU screendump capture helper/docs contract"] +def check_displayengine_ovmf_visual_validation_contract(root: Path) -> list[str]: + script = root / DISPLAYENGINE_OVMF_VISUAL_HELPER + manual_doc = root / DISPLAYENGINE_OVMF_VISUAL_DOC + validation_doc = root / "Docs" / "ProductizationValidationMatrix.md" + validation_doc_zh = root / "Docs" / "ProductizationValidationMatrix.zh-CN.md" + + for path in (script, manual_doc, validation_doc, validation_doc_zh): + if not path.exists(): + raise SmokeFailure(f"missing Phase35 DisplayEngine visual validation file: {path.relative_to(root)}") + + script_text = script.read_text(encoding="utf-8") + required_script_tokens = ( + "edk2-workspace.sh", + "DetectWorkspace", + "Scripts/build-ovmf-x64.sh", + "Scripts/capture-ovmf-x64.sh", + "MODERN_SETUP_DISPLAY_ENGINE=native", + "MODERN_SETUP_DISPLAY_ENGINE=modern", + "variants=(native modern)", + "GENERATE_ONLY", + "Build/ModernSetupPkgOverlay", + "CAPTURE_OUT_DIR", + "${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64", + "CAPTURE_WORK_DIR", + "Build/ModernSetupPkgCapture/DisplayEngineOvmfX64", + "overlays/${variant}", + "firmware/${variant}", + "displayengine-ovmf-x64-${variant}", + "--mode dry-run|generate-only|build|capture", + "BOOT_WAIT_SECONDS", + "SENDKEY_SEQUENCE", + "screendump", + "does not inspect pixels", + ) + for token in required_script_tokens: + if token not in script_text: + raise SmokeFailure(f"{DISPLAYENGINE_OVMF_VISUAL_HELPER} missing Phase35 token: {token}") + + prohibited_script_fragments = ( + "rm -rf", + "SetVariable", + "HiiSetBrowserData", + "HiiUpdateForm", + "RouteConfig", + "ExtractConfig", + "EFI_HII_CONFIG_ACCESS_PROTOCOL", + ) + for fragment in prohibited_script_fragments: + if fragment in script_text: + raise SmokeFailure(f"{DISPLAYENGINE_OVMF_VISUAL_HELPER} contains prohibited Phase35 fragment: {fragment}") + + doc_text = "\n".join( + ( + manual_doc.read_text(encoding="utf-8"), + validation_doc.read_text(encoding="utf-8"), + validation_doc_zh.read_text(encoding="utf-8"), + ) + ) + required_doc_tokens = ( + "capture-displayengine-ovmf-x64.sh", + "MODERN_SETUP_DISPLAY_ENGINE=native", + "MODERN_SETUP_DISPLAY_ENGINE=modern", + "${TMPDIR:-/tmp}/modernsetup-qemu/displayengine-ovmf-x64", + "overlays/native", + "overlays/modern", + "firmware/native", + "firmware/modern", + "Static smoke", + "Generate-only", + "Build", + "QEMU boot", + "Visual screenshot", + "does not inspect pixels", + "not mark visual equivalence as verified", + ) + for token in required_doc_tokens: + if token not in doc_text: + raise SmokeFailure(f"Phase35 DisplayEngine visual docs missing token: {token}") + + visual_verified_patterns = ( + re.compile(r"Phase35[^\n]{0,80}\bVerified\b", re.IGNORECASE), + re.compile(r"DisplayEngine[^\n]{0,80}\bVerified\b", re.IGNORECASE), + ) + for pattern in visual_verified_patterns: + if pattern.search(doc_text): + raise SmokeFailure("Phase35 DisplayEngine visual docs must not mark visual validation as Verified") + + return ["PASS Phase35 DisplayEngine OVMF X64 native-vs-modern visual validation foundation"] + + def strip_c_comments(text: str) -> str: text = re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL) text = re.sub(r"//.*", "", text) @@ -2154,6 +2246,7 @@ def main() -> int: messages.extend(check_ip_hygiene_notices(root)) messages.extend(check_edk2_baseline_contract(root)) messages.extend(check_ovmf_capture_helper_contract(root)) + messages.extend(check_displayengine_ovmf_visual_validation_contract(root)) messages.extend(check_xarch_docs_contract(root)) messages.extend(check_xarch_runner_contract(root)) messages.extend(check_xarch_runner_artifact_output(root))