From 81633f6d5a47572ee8c8864592f7f7f2b09a70d2 Mon Sep 17 00:00:00 2001 From: Jose Olguin Lagos Date: Fri, 17 Jul 2026 19:39:07 -0400 Subject: [PATCH] Validate synthetic SPIR-V in CI (#335) --- .github/workflows/workflow.yml | 33 +++++++++++++++++ scripts/validate-synthetic-spirv.sh | 55 +++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100755 scripts/validate-synthetic-spirv.sh diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 31300e59..3abd1263 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -159,6 +159,11 @@ jobs: NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages PUBLISH_DIR: ${{ github.workspace }}/artifacts/publish/${{ matrix.rid }} RELEASE_DIR: ${{ github.workspace }}/artifacts/release + SPIRV_HEADERS_COMMIT: ad9184e76a66b1001c29db9b0a3e87f646c64de0 + # SpirvModuleBuilder emits SPIR-V 1.5 and VulkanVideoPresenter requests Vulkan 1.2. + SPIRV_TARGET_ENV: vulkan1.2 + SPIRV_TOOLS_COMMIT: 0539c81f69a3daeb706fd3477dca61435b475156 + SPIRV_TOOLS_VERSION: v2026.2 steps: - name: Checkout repository uses: actions/checkout@v6 @@ -183,6 +188,34 @@ jobs: - name: Run tests run: dotnet test SharpEmu.slnx -c Release --no-build --verbosity normal + - name: Build pinned SPIRV-Tools + if: matrix.rid == 'linux-x64' + run: | + git clone --no-checkout --filter=blob:none https://github.com/KhronosGroup/SPIRV-Tools.git "$RUNNER_TEMP/spirv-tools" + git -C "$RUNNER_TEMP/spirv-tools" checkout --detach "$SPIRV_TOOLS_COMMIT" + test "$(git -C "$RUNNER_TEMP/spirv-tools" rev-parse HEAD)" = "$SPIRV_TOOLS_COMMIT" + + git clone --no-checkout --filter=blob:none https://github.com/KhronosGroup/SPIRV-Headers.git "$RUNNER_TEMP/spirv-tools/external/spirv-headers" + git -C "$RUNNER_TEMP/spirv-tools/external/spirv-headers" checkout --detach "$SPIRV_HEADERS_COMMIT" + test "$(git -C "$RUNNER_TEMP/spirv-tools/external/spirv-headers" rev-parse HEAD)" = "$SPIRV_HEADERS_COMMIT" + + cmake -S "$RUNNER_TEMP/spirv-tools" -B "$RUNNER_TEMP/spirv-tools-build" \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DSPIRV_SKIP_TESTS=ON \ + -DSPIRV_WERROR=OFF + cmake --build "$RUNNER_TEMP/spirv-tools-build" --target spirv-val + + - name: Generate and validate synthetic SPIR-V + if: matrix.rid == 'linux-x64' + run: | + dotnet run --project tools/SharpEmu.Tools.ShaderDump/SharpEmu.Tools.ShaderDump.csproj -c Release -- artifacts/shader-dump + scripts/validate-synthetic-spirv.sh \ + "$RUNNER_TEMP/spirv-tools-build/tools/spirv-val" \ + "$SPIRV_TOOLS_VERSION" \ + "$SPIRV_TARGET_ENV" \ + artifacts/shader-dump + - name: Publish ${{ matrix.rid }} CLI run: dotnet publish src/SharpEmu.CLI/SharpEmu.CLI.csproj -c Release -r ${{ matrix.rid }} --self-contained true --no-restore -p:PublishDir="$PUBLISH_DIR" diff --git a/scripts/validate-synthetic-spirv.sh b/scripts/validate-synthetic-spirv.sh new file mode 100755 index 00000000..23b2152d --- /dev/null +++ b/scripts/validate-synthetic-spirv.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Copyright (C) 2026 SharpEmu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +set -euo pipefail + +if [ "$#" -ne 4 ]; then + echo "usage: $0 " >&2 + exit 2 +fi + +validator=$1 +expected_version=$2 +target_env=$3 +module_directory=$4 + +if [ ! -x "$validator" ]; then + echo "SPIR-V validator is not executable: $validator" >&2 + exit 2 +fi + +if [ ! -d "$module_directory" ]; then + echo "SPIR-V module directory does not exist: $module_directory" >&2 + exit 2 +fi + +validator_version="$("$validator" --version | head -n 1)" +if [[ "$validator_version" != *"SPIRV-Tools $expected_version"* ]]; then + echo "unexpected SPIRV-Tools version: $validator_version (expected $expected_version)" >&2 + exit 2 +fi + +echo "Validator: $validator_version" +echo "Target environment: $target_env" + +mapfile -d '' modules < <(find "$module_directory" -type f -name '*.spv' -print0 | sort -z) +if [ "${#modules[@]}" -eq 0 ]; then + echo "no SPIR-V modules found in $module_directory" >&2 + exit 1 +fi + +failures=0 +for module in "${modules[@]}"; do + echo "Validating module: $module" + if ! "$validator" --target-env "$target_env" "$module"; then + echo "SPIR-V validation failed: $module" >&2 + failures=1 + fi +done + +if [ "$failures" -ne 0 ]; then + exit 1 +fi + +echo "Validated ${#modules[@]} synthetic SPIR-V modules."