Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions .github/workflows/cpu-contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
name: CPU Contracts

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: cpu-contracts-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
cpu-contracts:
name: Windows x64 CPU contracts
runs-on: windows-2022
timeout-minutes: 20

defaults:
run:
shell: pwsh

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1
persist-credentials: false

- name: Select and report toolchain
run: |
$ErrorActionPreference = "Stop"
$MinimumCMakeVersion = [Version]"4.0.1"

function Get-CMakeVersion([string]$Executable)
{
$VersionOutput = @(& $Executable --version 2>&1)
$VersionMatch = [regex]::Match(
[string]::Join("`n", $VersionOutput),
"(?m)^cmake version ([0-9]+(?:\.[0-9]+)+)"
)
if (-not $VersionMatch.Success)
{
throw "Unable to determine CMake version from $Executable"
}
return [Version]($VersionMatch.Groups[1].Value)
}

$SelectedCMakeVersion = Get-CMakeVersion "cmake"
if ($SelectedCMakeVersion -lt $MinimumCMakeVersion)
{
$AndroidCMakeRoot = Join-Path $env:ANDROID_HOME "cmake"
$Candidates = @(
Get-ChildItem -LiteralPath $AndroidCMakeRoot -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$CandidateExecutable = Join-Path $_.FullName "bin\cmake.exe"
if (Test-Path -LiteralPath $CandidateExecutable)
{
$CandidateVersion = Get-CMakeVersion $CandidateExecutable
if ($CandidateVersion -ge $MinimumCMakeVersion)
{
[PSCustomObject]@{
Bin = Split-Path -Parent $CandidateExecutable
Version = $CandidateVersion
}
}
}
} |
Sort-Object Version -Descending
)
if ($Candidates.Count -eq 0)
{
throw "CMake $MinimumCMakeVersion or newer is not installed on the runner"
}

$Selected = $Candidates[0]
$Selected.Bin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
$env:Path = "$($Selected.Bin);$env:Path"
$SelectedCMakeVersion = Get-CMakeVersion "cmake"
}

$PythonVersion = & python --version 2>&1 | Select-Object -First 1
if ($PythonVersion -notmatch "^Python 3\.")
{
throw "Python 3 is required for the complete CPU contract lane"
}

$VsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$VisualStudioVersion = & $VsWhere -latest -products * `
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
-property installationVersion
if (-not $VisualStudioVersion)
{
throw "Visual Studio 2022 C++ tools are required"
}
if ($VisualStudioVersion -notmatch "^17\.")
{
throw "Expected Visual Studio 2022, found $VisualStudioVersion"
}

$Commit = git rev-parse HEAD
$EnvironmentEvidence = @(
"## CPU Contract Environment"
""
"- Commit: ``$Commit``"
"- Runner: ``$env:ImageOS`` / ``$env:ImageVersion``"
"- CMake: ``$SelectedCMakeVersion``"
"- Python: ``$PythonVersion``"
"- Visual Studio: ``$VisualStudioVersion``"
"- Configure preset: ``vs2022-x64``"
"- Build presets: ``cpu-debug``, ``cpu-release``"
"- Test presets: ``test-cpu-debug``, ``test-cpu-release``"
)
$EnvironmentEvidence | Write-Output
$EnvironmentEvidence |
Add-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Encoding utf8

- name: Configure
run: cmake --preset vs2022-x64

- name: Build CPU contracts (Debug)
run: cmake --build --preset cpu-debug

- name: Test CPU contracts (Debug)
run: ctest --preset test-cpu-debug

- name: Build CPU contracts (Release)
run: cmake --build --preset cpu-release

- name: Test CPU contracts (Release)
run: ctest --preset test-cpu-release

- name: Report CPU contract result
run: |
$ErrorActionPreference = "Stop"
$DebugDiscovery = ctest --preset test-cpu-debug --show-only=json-v1 |
ConvertFrom-Json
if ($LASTEXITCODE -ne 0)
{
throw "Unable to discover Debug CPU tests"
}
$ReleaseDiscovery = ctest --preset test-cpu-release --show-only=json-v1 |
ConvertFrom-Json
if ($LASTEXITCODE -ne 0)
{
throw "Unable to discover Release CPU tests"
}
$ResultEvidence = @(
""
"## CPU Contract Result"
""
"- Debug: **Pass** ($($DebugDiscovery.tests.Count) tests)"
"- Release: **Pass** ($($ReleaseDiscovery.tests.Count) tests)"
)
$ResultEvidence | Write-Output
$ResultEvidence |
Add-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Encoding utf8
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cmake -S . -B Build

# 构建与运行
cmake --build Build --config Debug
& .\Build\Debug\WaveEngine.exe
& .\Build\Debug\WaveEditor.exe
```

`Rebuild.bat` 复用 `Build/`,不是 clean rebuild。Visual Studio 产物在 `Build/<Config>/`;构建后复制 `Engine/ThirdParty/bin/` 的运行库。
Expand All @@ -96,8 +96,8 @@ ctest --test-dir Build -C Debug --output-on-failure
| Release 语义、assert | `ctest --test-dir Build -C Release -R CoreRuntimeContracts --output-on-failure` |
| RenderGraph、Pass | Debug 下设置 `WAVE_RG_STRICT=1`,验证真实光栅路径和日志 |
| Path Tracing | 仅在 DXR Tier 1.1 硬件验证;硬件不足明确记为未运行 |
| MCP framing、数值或资产输入 | `py -3 Tests/mcp_asset_input_contracts.py Build/Debug/WaveEngine.exe` |
| WEMesh、模型依赖、缓存 | `py -3 Tests/wemesh_cache_contracts.py Build/Debug/WaveEngine.exe` |
| MCP framing、数值或资产输入 | `py -3 Tests/mcp_asset_input_contracts.py Build/Debug/WaveEditor.exe` |
| WEMesh、模型依赖、缓存 | `py -3 Tests/wemesh_cache_contracts.py Build/Debug/WaveEditor.exe` |
| 坐标、Rotator、相机、导入或序列化 | 同时运行 Core Runtime 与 WEMesh 契约 |
| RHI 异常/关闭 | Debug 设置 `WAVE_RHI_INJECT_FAILURE=1`,应经 quarantine 非零退出 |
| Profiler | Start/Stop、`.wetrace`、live、Viewer、多帧分析、dropped/overflow |
Expand All @@ -110,7 +110,7 @@ ctest --test-dir Build -C Debug --output-on-failure

### 生命周期、RHI 与线程

- 入口为 `Engine/Source/WaveEngine.cpp`。启动顺序:Log → Window → Input → RHI/worker → ShaderMap → Scene → Renderer/UI → MCP。
- 入口为 `Engine/Source/WaveEditor.cpp`。启动顺序:Log → Window → Input → RHI/worker → ShaderMap → Scene → Renderer/UI → MCP。
- 主循环顺序:Input → MCP main-thread drain → Scene Tick → Renderer。MCP drain 不依赖窗口可渲染状态。
- MCP 只能在 Renderer/UI 完成工具注册后启动。关闭顺序:拒绝新任务 → 停 MCP → 等 RHI/GPU idle → 销毁 GPU-backed UI/Renderer/cache → Scene/Shader/Input → `FDynamicRHI::Destroy()` → Window。
- Renderer 必须跨过顶层异常保持存活。无法证明 GPU idle 时停止 worker 并经 `_Exit` quarantine,不能执行不安全 GPU teardown。
Expand Down
Loading