vdi-cloud/tools/set-2k-display.ps1
宋一鸣 6c7b68d1ce 功能:真2K串流与重启持久化,优化客户端渲染和帧率配置
三端统一2560x1440,盒子使用297MHz HDMI时序并保留1080p回退;Windows脚本动态定位VDD恢复2K。串流默认2K20/30Mbps,使用GLES2,设置页支持20/24FPS及自定义值。保持Windows正常光标,记录NVENC阶段性实测和GPU重启后Code43未恢复的限制。
2026-11-02 16:40:22 +08:00

82 lines
3.5 KiB
PowerShell

$ErrorActionPreference = 'Stop'
Add-Type @'
using System;
using System.Runtime.InteropServices;
public static class VdiDisplayMode {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Device {
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string Name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Description;
public int Flags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Key;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Mode {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string name;
public short spec, driver, size, extra;
public int fields, x, y, orientation, fixedOutput;
public short color, duplex, yres, tt, collate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string form;
public short logPixels;
public int bpp, width, height, flags, hz, icmMethod, icmIntent, media, dither,
reserved1, reserved2, panWidth, panHeight;
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern bool EnumDisplayDevices(string name, uint index, ref Device dev, uint flags);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern bool EnumDisplaySettings(string name, int index, ref Mode mode);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern int ChangeDisplaySettingsEx(string name, ref Mode mode, IntPtr window, uint flags, IntPtr param);
public static string Find() {
for (uint i = 0; ; i++) {
var d = new Device();
d.cb = Marshal.SizeOf(typeof(Device));
if (!EnumDisplayDevices(null, i, ref d, 0)) return null;
if ((d.Flags & 1) != 0 && d.Description.IndexOf("Virtual Display Driver", StringComparison.OrdinalIgnoreCase) >= 0)
return d.Name;
}
}
public static string Current(string name) {
var m = new Mode();
m.size = (short)Marshal.SizeOf(typeof(Mode));
if (!EnumDisplaySettings(name, -1, ref m)) return "unavailable";
return m.width + "x" + m.height + "@" + m.hz;
}
public static int Apply(string name) {
for (int i = 0; ; i++) {
var m = new Mode();
m.size = (short)Marshal.SizeOf(typeof(Mode));
if (!EnumDisplaySettings(name, i, ref m)) return -99;
if (m.width == 2560 && m.height == 1440 && m.hz == 30) {
m.fields = 0x80000 | 0x100000 | 0x400000;
int test = ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 2, IntPtr.Zero);
if (test != 0) return test;
return ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 1, IntPtr.Zero);
}
}
}
}
'@
$log = 'C:/ProgramData/VDI/set-2k-result.txt'
try {
for ($i = 0; $i -lt 12; $i++) {
$dev = [VdiDisplayMode]::Find()
if ($dev) {
$result = [VdiDisplayMode]::Apply($dev)
$mode = [VdiDisplayMode]::Current($dev)
if ($result -eq 0 -and $mode -eq '2560x1440@30') {
"$(Get-Date -Format o) device=$dev result=0 mode=$mode" | Set-Content $log
exit 0
}
}
Start-Sleep 5
}
throw "2K mode not applied: device=$dev result=$result mode=$mode"
} catch {
"$(Get-Date -Format o) ERROR $_" | Set-Content $log
exit 1
}