mirror of
https://github.com/stride3d/stride.git
synced 2026-10-12 02:23:23 +00:00
The test host gets the same per-API assembly layout as Game Studio and picks the API from STRIDE_GRAPHICS_API at startup. The workflow runs the fixtures once per API (Direct3D11, Direct3D12, Vulkan); the Vulkan job uses Lavapipe with the validation layers, without synchronization validation: on the 4-core runner it starves the asset build and the fixtures time out. The games the fixtures build stay on Direct3D11. A manual run can pick one API. The Windows Vulkan setup (SDK, validation layer, Lavapipe ICD) becomes a composite action shared with the game and enduser workflows.
207 lines
9.8 KiB
YAML
207 lines
9.8 KiB
YAML
name: Test GameStudio (Screenshots)
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
build-type:
|
|
description: Build
|
|
default: Debug
|
|
type: choice
|
|
options:
|
|
- Debug
|
|
- Release
|
|
graphics-api:
|
|
description: Only this graphics API (blank = all)
|
|
default: ''
|
|
type: choice
|
|
options:
|
|
- ''
|
|
- Direct3D11
|
|
- Direct3D12
|
|
- Vulkan
|
|
workflow_call:
|
|
inputs:
|
|
build-type:
|
|
default: Debug
|
|
type: string
|
|
secrets:
|
|
ANTHROPIC_API_KEY:
|
|
required: false
|
|
schedule:
|
|
# Daily at 05:17 UTC — offset off top-of-hour to avoid GitHub Actions cron load spikes;
|
|
# gap from test-enduser (04:37) so they don't compete for runners.
|
|
- cron: '17 5 * * *'
|
|
|
|
concurrency:
|
|
group: test-windows-editor-${{ github.event.pull_request.number || github.sha }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# Editor drift is non-deterministic enough that the LPIPS comparator relies on Claude vision as a
|
|
# tiebreak on borderline frames. With ANTHROPIC_API_KEY the comparator resolves those inline; without
|
|
# it (typical on fork PRs, where secrets aren't exposed) the borderline frames are captured and marked
|
|
# "deferred" in <fixture>/vision-deferred.json, and pr-screenshot-vision-gate re-judges them with the
|
|
# key on the uploaded artifacts. Hard LPIPS drift (no vision tiebreak) still fails here regardless.
|
|
#
|
|
# Fork-friendly: schedule fires only when STRIDE_ENABLE_SCHEDULED_CI is set on the repo.
|
|
# workflow_dispatch / workflow_call always run.
|
|
Run:
|
|
if: >
|
|
github.event_name != 'schedule'
|
|
|| vars.STRIDE_ENABLE_SCHEDULED_CI == 'true'
|
|
name: Windows (Editor, ${{ matrix.graphics-api }}, ${{ inputs.build-type || 'Debug' }})
|
|
runs-on: windows-2025-vs2026
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Game Studio runs on each API; the games the fixtures build stay on Direct3D11.
|
|
graphics-api: ${{ fromJSON(inputs.graphics-api && format('["{0}"]', inputs.graphics-api) || '["Direct3D11", "Direct3D12", "Vulkan"]') }}
|
|
env:
|
|
# Read by GraphicsApiSelector at Game Studio startup.
|
|
STRIDE_GRAPHICS_API: ${{ matrix.graphics-api }}
|
|
# No STRIDE_VULKAN_SYNC_VALIDATION here: on Lavapipe it slows the thumbnails to about one per second, and the
|
|
# fixtures time out. The game tests and the enduser samples run the same rendering code with it on.
|
|
# MSBuild property (read from the environment): a fresh checkout only builds Direct3D11, so
|
|
# stage the requested API next to it.
|
|
StrideGraphicsApis: ${{ matrix.graphics-api != 'Direct3D11' && format('Direct3D11;{0}', matrix.graphics-api) || '' }}
|
|
DOTNET_DbgEnableMiniDump: "1"
|
|
DOTNET_DbgMiniDumpType: "1"
|
|
DOTNET_DbgMiniDumpName: "${{ github.workspace }}\\crash-dumps\\dotnet_%p.dmp"
|
|
# Crash-report store (asset compiler, GameStudio) lands in the uploaded crash-dumps artifact.
|
|
STRIDE_CRASH_DIR: "${{ github.workspace }}\\crash-dumps\\crash-reports"
|
|
steps:
|
|
# Bootstrap .github so the local composite action below is resolvable pre-checkout.
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
sparse-checkout: .github
|
|
# Full checkout (no samples exclude): the editor build preprocesses the template source
|
|
# under samples/NewGame via Stride.Templates.Games.
|
|
- uses: ./.github/actions/stride-checkout
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Configure crash dumps
|
|
shell: pwsh
|
|
run: |
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f
|
|
$dumpDir = "${{ github.workspace }}\crash-dumps"
|
|
New-Item -Path $dumpDir -ItemType Directory -Force | Out-Null
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d $dumpDir /f
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 1 /f
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f
|
|
|
|
# PackageStore.LoadDefaultSettings(null) only reads the user + machine NuGet configs,
|
|
# not the workspace nuget.config — register bin/packages in the user config.
|
|
- name: Register bin/packages with user NuGet config
|
|
shell: pwsh
|
|
run: |
|
|
New-Item -Path "$env:APPDATA\NuGet" -ItemType Directory -Force | Out-Null
|
|
dotnet nuget add source "${{ github.workspace }}\bin\packages" --name stride-local --configfile "$env:APPDATA\NuGet\NuGet.Config"
|
|
|
|
# GH runners default to a 0x0 fallback display; WPF clamps the editor to that. The
|
|
# composite action installs an IDD virtual display so we get a real desktop surface.
|
|
- name: Set display resolution
|
|
uses: ./.github/actions/set-display-resolution-vdd
|
|
with:
|
|
width: '3840'
|
|
height: '2160'
|
|
|
|
# No GPU on the runner: Lavapipe, with the validation layers
|
|
- name: Set up Vulkan
|
|
if: matrix.graphics-api == 'Vulkan'
|
|
uses: ./.github/actions/setup-vulkan-windows
|
|
|
|
- name: Build Stride.GameStudio.AutoTesting
|
|
run: |
|
|
dotnet build sources\editor\Stride.GameStudio.AutoTesting\Stride.GameStudio.AutoTesting.csproj `
|
|
-nr:false -v:m -p:WarningLevel=0 `
|
|
-p:Configuration=${{ inputs.build-type || 'Debug' }}
|
|
|
|
- name: Build Stride.Editor.Tests
|
|
run: |
|
|
dotnet build tests\editor\Stride.Editor.Tests.csproj `
|
|
-nr:false -v:m -p:WarningLevel=0 `
|
|
-p:Configuration=${{ inputs.build-type || 'Debug' }}
|
|
|
|
# Pre-test snapshot of NuGet state: bin/packages timestamps+sizes (catches partial writes
|
|
# or out-of-order packing), NuGet global cache extractions for Stride.*, and the user
|
|
# nuget config (which sources/mapping the sample restore will see).
|
|
- name: Diagnostic — NuGet state pre-test
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "=== bin/packages Stride.* (name, size, mtime) ==="
|
|
Get-ChildItem bin\packages\Stride.*.nupkg -ErrorAction SilentlyContinue |
|
|
Format-Table Name, Length, LastWriteTimeUtc -AutoSize
|
|
Write-Host "=== NuGet global cache: stride.* extractions ==="
|
|
$cache = "$env:UserProfile\.nuget\packages"
|
|
if (Test-Path $cache) {
|
|
Get-ChildItem "$cache\stride.*" -Directory -ErrorAction SilentlyContinue |
|
|
Get-ChildItem -Directory -ErrorAction SilentlyContinue |
|
|
Format-Table FullName, LastWriteTimeUtc -AutoSize
|
|
} else { "No global packages cache at $cache" }
|
|
Write-Host "=== NuGet sources (user config) ==="
|
|
dotnet nuget list source --configfile "$env:APPDATA\NuGet\NuGet.Config"
|
|
Write-Host "=== User NuGet.Config ==="
|
|
if (Test-Path "$env:APPDATA\NuGet\NuGet.Config") { Get-Content "$env:APPDATA\NuGet\NuGet.Config" }
|
|
|
|
# EditorScreenshotTests.Capture is an xunit [Theory] over Fixtures(); each entry spawns
|
|
# the AutoTesting CLI as a subprocess (per-fixture WPF singleton-state isolation),
|
|
# snapshots the runner output into <worktree>/ui-test-out-dpi<N>/<fixture>/, then runs
|
|
# ScreenshotComparator.Compare against tests/editor/baselines/dpi<N>/. ANTHROPIC_API_KEY
|
|
# opts the comparator into Claude vision second-opinions on frames that exceed LPIPS —
|
|
# cost is bounded because Claude only fires on already-failing frames.
|
|
- name: Run editor screenshot tests
|
|
env:
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
run: |
|
|
dotnet test tests\editor\Stride.Editor.Tests.csproj `
|
|
--no-build `
|
|
--filter "FullyQualifiedName~Stride.Editor.Tests.EditorScreenshotTests" `
|
|
--logger "trx;LogFileName=editor-screenshots.trx" `
|
|
--results-directory TestResults `
|
|
-p:Configuration=${{ inputs.build-type || 'Debug' }}
|
|
|
|
- name: Publish test report
|
|
if: always()
|
|
uses: phoenix-actions/test-reporting@v16
|
|
with:
|
|
name: 'Editor screenshot regression (${{ matrix.graphics-api }})'
|
|
path: TestResults/*.trx
|
|
reporter: dotnet-trx
|
|
output-to: step-summary
|
|
|
|
# Named screenshots-* so the trusted vision gate's download pattern (screenshots-*) picks it up
|
|
# alongside the enduser captures and re-judges any deferred frames.
|
|
- name: Upload screenshots
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: screenshots-editor-${{ matrix.graphics-api }}
|
|
path: ui-test-out-dpi*/
|
|
if-no-files-found: warn
|
|
|
|
- name: Upload crash dumps
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: editor-crash-dumps-${{ matrix.graphics-api }}
|
|
path: crash-dumps/
|
|
if-no-files-found: ignore
|
|
|
|
# Sample's project.assets.json (NuGet resolution record) + csproj/sln, plus the actual
|
|
# Stride.Engine/Core.Serialization DLLs that ended up in the sample's bin (their content
|
|
# reveals which version was materialized, independent of what assets.json claims).
|
|
- name: Upload generated sample obj/ + materialized engine DLLs
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: editor-sample-obj-${{ matrix.graphics-api }}
|
|
path: |
|
|
C:\Users\runneradmin\AppData\Local\Temp\stride-editor-tests\**\obj\project.assets.json
|
|
C:\Users\runneradmin\AppData\Local\Temp\stride-editor-tests\**\*.csproj
|
|
C:\Users\runneradmin\AppData\Local\Temp\stride-editor-tests\**\*.sln
|
|
C:\Users\runneradmin\AppData\Local\Temp\stride-editor-tests\**\bin\**\Stride.Engine.dll
|
|
C:\Users\runneradmin\AppData\Local\Temp\stride-editor-tests\**\bin\**\Stride.Core.Serialization.dll
|
|
if-no-files-found: warn
|
|
retention-days: 7
|