功能:完善2K串流、显示恢复与输入优化

This commit is contained in:
songyiming committed 2026-11-03 13:43:50 +08:00
1 parent e47b01beec
commit 938ec97cce
95 files changed
+5788 -72

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
param(
[string]$SunshineLogPath = "",
[int]$MaxLogAgeMinutes = 30
)
# 只读验收脚本:不重启 VM、设备、VFIO 或 Sunshine,不修改任何配置。
# 退出码 0 才表示当前状态满足“可继续做串流性能验收”的前置条件。
$ErrorActionPreference = "Stop"
$ok = $true
function Report([string]$Name, [bool]$Passed, [string]$Detail) {
$state = if ($Passed) { "PASS" } else { "FAIL" }
Write-Output ("[{0}] {1}: {2}" -f $state, $Name, $Detail)
}
$nvidiaCommand = Get-Command nvidia-smi -ErrorAction SilentlyContinue
if ($null -eq $nvidiaCommand) {
Report "nvidia-smi" $false "命令不存在"
$ok = $false
} else {
$ErrorActionPreference = 'Continue'
$gpuText = & $nvidiaCommand.Source --query-gpu=name,driver_version,pstate --format=csv,noheader 2>&1
$queryExitCode = $LASTEXITCODE
$ErrorActionPreference = 'Stop'
if ($queryExitCode -ne 0 -or [string]::IsNullOrWhiteSpace(($gpuText -join ""))) {
Report "nvidia-smi" $false (($gpuText -join " ").Trim())
$ok = $false
} else {
Report "nvidia-smi" $true (($gpuText -join " ").Trim())
}
}
try {
$displayAdapters = @(Get-CimInstance Win32_VideoController |
Where-Object { $_.Name -match "NVIDIA|GeForce|Quadro|Tesla" })
$healthy = @($displayAdapters | Where-Object { $_.ConfigManagerErrorCode -eq 0 }).Count -gt 0
Report "NVIDIA PnP" $healthy (($displayAdapters | ForEach-Object { "$($_.Name): code=$($_.ConfigManagerErrorCode)" }) -join "; ")
$ok = $ok -and $healthy
if (-not ('VdiDiagnostics.D3DProbe' -as [type])) {
Add-Type -Path (Join-Path $PSScriptRoot 'probe-nvidia-d3d.cs')
}
$dxgi = @([VdiDiagnostics.D3DProbe]::Check())
$healthy = @($dxgi | Where-Object { $_.DeviceResult -eq 0 }).Count -gt 0
$detail = if ($dxgi.Count) { ($dxgi | ForEach-Object { '{0}: HRESULT=0x{1:X8}' -f $_.Name,$_.DeviceResult }) -join '; ' } else { 'DXGI did not enumerate an NVIDIA adapter' }
Report "NVIDIA DXGI + D3D11" $healthy $detail
$ok = $ok -and $healthy
} catch {
Report "NVIDIA DXGI + D3D11" $false $_.Exception.Message
$ok = $false
}
if ([string]::IsNullOrWhiteSpace($SunshineLogPath)) {
$candidates = @(
"C:\Program Files\Sunshine\config\sunshine.log",
"C:\ProgramData\Sunshine\config\sunshine.log"
)
$SunshineLogPath = $candidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
}
if ([string]::IsNullOrWhiteSpace($SunshineLogPath) -or -not (Test-Path -LiteralPath $SunshineLogPath)) {
Report "Sunshine encoder" $false "找不到 sunshine.log;不能证明实际使用 h264_nvenc"
$ok = $false
} else {
# Encoder discovery/probing can mention both NVENC and x264. Inspect only
# the most recent actual creation, with a timestamp, never the entire history.
$pattern = '\[(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\].*Creating encoder \[(?<encoder>[^\]]+)\]'
$matches = [regex]::Matches((Get-Content -LiteralPath $SunshineLogPath -Raw), $pattern)
$healthy = $false
$detail = '没有实际编码器创建记录;请连接Moonlight并播放测试动画'
if ($matches.Count -gt 0) {
$entry = $matches[$matches.Count - 1]
$encoder = $entry.Groups['encoder'].Value
$createdAt = [datetime]::Parse($entry.Groups['time'].Value, [Globalization.CultureInfo]::InvariantCulture)
$ageMinutes = ((Get-Date) - $createdAt).TotalMinutes
$healthy = $encoder -eq 'h264_nvenc' -and $ageMinutes -ge 0 -and $ageMinutes -le $MaxLogAgeMinutes
$detail = '{0}, created {1}, age {2:N1} min' -f $encoder,$createdAt,$ageMinutes
}
Report "Sunshine active encoder" $healthy $detail
$ok = $ok -and $healthy
}
if ($nvidiaCommand) {
$ErrorActionPreference = 'Continue'
$activity = & $nvidiaCommand.Source --query-gpu=encoder.stats.sessionCount,utilization.encoder --format=csv,noheader,nounits 2>&1
$queryExitCode = $LASTEXITCODE
$ErrorActionPreference = 'Stop'
$healthy = $false
if ($queryExitCode -eq 0) {
foreach ($row in $activity) {
if ([string]$row -match '^\s*(\d+),\s*(\d+)\s*$') {
if ([int]$Matches[1] -gt 0 -and [int]$Matches[2] -gt 0) { $healthy = $true }
}
}
}
Report "NVENC session/utilization" $healthy ($activity -join '; ')
$ok = $ok -and $healthy
}
if ($ok) {
Write-Output "GPU/NVENC 前置验收通过:可以继续做 Moonlight 帧率与延迟测试。"
exit 0
}
Write-Output "GPU/NVENC 前置验收失败:不要把当前状态作为硬编码性能结果。"
exit 1