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))