Skip to content

fix(vdd): VDD拓扑范围限定 + 延迟销毁机制,修复首次连接失败和切换应用GUID失效#527

Open
qiin2333 wants to merge 2 commits intomasterfrom
fix/vdd-display-mode-only-vdd-devices
Open

fix(vdd): VDD拓扑范围限定 + 延迟销毁机制,修复首次连接失败和切换应用GUID失效#527
qiin2333 wants to merge 2 commits intomasterfrom
fix/vdd-display-mode-only-vdd-devices

Conversation

@qiin2333
Copy link
Owner

@qiin2333 qiin2333 commented Mar 13, 2026

问题

dff5a728 的重构后,VDD 模式出现两个问题:

1. 首次连接失败(物理显示器干扰)

apply_config 不再跳过 VDD 模式的显示设置,但 get_current_topology_metadata 返回了整个系统拓扑(物理+VDD),导致 handle_display_mode_configuration 尝试对所有设备(包括可能不稳定的物理显示器)设置分辨率/刷新率。当物理显示器设备路径查询失败时,整个流程中断。

2. 切换应用时 VDD 陈旧 GUID(Cancel → Launch)

用户切换游戏时,nvhttp Cancel handler 无条件调用 restore_state() 销毁 VDD,persistent_data 中保留了旧 GUID。紧接着 Launch 创建新 VDD(新 GUID),后续 set_display_modes 用旧 GUID 查找设备失败。

解决方案

Commit 1: VDD 拓扑范围限定

  • get_current_topology_metadata: metadata.current_topology 改为仅包含 VDD 设备所在的拓扑组,不包含无关的物理显示器
  • wait_for_display_stability: 拓扑比较改为 subset 检查,避免 VDD 模式下因部分拓扑不匹配导致 5 秒超时等待

Commit 2: 延迟 VDD 销毁(Grace Period)

当 Cancel 触发 restore_state() 时,如果 VDD 存在且非常驻模式,不再立即销毁,而是设置 5 秒延迟:

  • Grace Period 内新 Launch 到来:取消计时器,复用现有 VDD(同 GUID、同 persistent_data),无拓扑闪烁
  • Grace Period 过期:执行完整恢复(VDD 销毁 + 拓扑还原)
  • 模式变更安全:如果新旧 vdd_prep 不同(例如从 ensure_only_display 切到 no_operation),先执行完整恢复再重新配置,避免 persistent_data 与新模式不匹配

附带修复:remove_stale_device_entries 模板参数从 std::unordered_map<string,T> 改为泛型 MapT,兼容 device_display_mode_map_tstd::map)。

影响范围

所有 VDD 显示模式都受益于延迟销毁,消除了应用切换时不必要的 VDD 销毁/重建循环。

修改文件

文件 变更
session.h 新增 deferred_restore_deferred_restore_reason_execute_deferred_restore()
session.cpp restore_state_impl 拆分为入口+延迟执行;configure_display 增加延迟恢复取消/模式变更处理
settings.cpp remove_stale_device_entries 模板泛型化
settings_topology.cpp get_current_topology_metadata 限定为 VDD-only 拓扑

Copilot AI review requested due to automatic review settings March 13, 2026 10:10
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 修复 Windows 下 VDD 模式首次连接串流失败的问题:在仅需要操作 VDD 的场景中,避免对整个系统拓扑(物理+VDD)进行显示模式/HDR 设置,从而规避物理显示器在 VDD 创建后短暂不稳定导致的失败。

Changes:

  • VDD 模式下 get_current_topology_metadata() 仅向 metadata 暴露包含 VDD 的拓扑组,限制后续模式/HDR 操作范围。
  • wait_for_display_stability() 改为对设备集合做 subset 检查,并仅查询 metadata 相关设备的当前显示模式。

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/platform/windows/display_device/settings_topology.cpp VDD 模式下构造 vdd-only 的 metadata.current_topology,避免对物理显示器做模式/HDR 查询与设置
src/platform/windows/display_device/settings.cpp 稳定性等待逻辑改为 subset 判断,并限制显示模式查询范围到 metadata 设备集合

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +459 to 478
// VDD模式:构建仅包含VDD设备所在组的拓扑用于 metadata
// 这样 handle_display_mode_configuration 和 handle_hdr_state_configuration
// 只会查询/设置VDD相关设备的模式,不会因为物理显示器状态不稳定而失败
active_topology_t vdd_only_topology;
for (const auto &group : current_topology) {
for (const auto &id : group) {
if (id == requested_device_id) {
vdd_only_topology.push_back(group);
break;
}
}
}

return handled_topology_result_t {
topology_pair_t {
current_topology,
current_topology },
topology_metadata_t {
current_topology,
vdd_only_topology,
{}, // 没有新启用的设备
Comment on lines +327 to +329
const auto current_device_ids = get_device_ids_from_topology(current_topology);
bool topology_stable = std::all_of(metadata_device_ids.begin(), metadata_device_ids.end(),
[&current_device_ids](const std::string &id) { return current_device_ids.count(id) > 0; });
@qiin2333 qiin2333 changed the title fix: VDD模式下仅操作VDD设备的显示设置,避免首次连接失败 fix: VDD模式下仅操作VDD设备的显示设置,修复陈旧GUID导致的模式设置失败 Mar 13, 2026
Copilot AI review requested due to automatic review settings March 13, 2026 15:08
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 聚焦于 Windows 下 VDD 模式的显示设置稳定性:将显示模式/HDR 等操作限定在 VDD 相关设备范围内,并在使用持久化数据前过滤已销毁设备的陈旧 GUID,避免首次连接/快速重连时因对不存在设备下发配置而失败。

Changes:

  • VDD 模式下 metadata.current_topology 改为仅包含 VDD 所在拓扑组,避免对物理显示器做不必要的模式/HDR 操作
  • 引入对持久化显示模式/HDR/主屏 GUID 的“陈旧设备”过滤逻辑,防止对已销毁 VDD 设备下发设置
  • 调整稳定性等待逻辑:VDD 模式下拓扑对比改为 subset 检查,并按 metadata 范围查询当前模式

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/platform/windows/display_device/settings_topology.cpp VDD 模式下构建仅含 VDD 组的 topology metadata,限制后续模式/HDR 操作范围
src/platform/windows/display_device/settings.cpp 新增过滤陈旧设备条目逻辑,并在模式/HDR/主屏处理入口使用;更新稳定性等待的拓扑比较与模式查询范围
src/display_device/session.cpp 在 no_operation 恢复路径中增加对持久化数据的清理调用,避免旧 VDD GUID 影响后续会话

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// 避免下一次 Launch 创建新 VDD 时,apply_config 使用旧 VDD 的 GUID
if (settings.has_persistent_data()) {
BOOST_LOG(info) << "清理残留的显示设备持久化数据(VDD 已销毁/重建后 GUID 会变化)";
settings.reset_persistence();
Comment on lines +462 to +469
active_topology_t vdd_only_topology;
for (const auto &group : current_topology) {
for (const auto &id : group) {
if (id == requested_device_id) {
vdd_only_topology.push_back(group);
break;
}
}
Comment on lines +67 to +88
template <typename T>
size_t
remove_stale_device_entries(std::unordered_map<std::string, T> &device_map) {
if (device_map.empty()) {
return 0;
}

const auto available_devices { enum_available_devices() };
size_t removed { 0 };
for (auto it = device_map.begin(); it != device_map.end();) {
if (available_devices.find(it->first) == available_devices.end()) {
BOOST_LOG(debug) << "Removing stale device entry (device no longer exists): " << it->first;
it = device_map.erase(it);
++removed;
}
else {
++it;
}
}

return removed;
}
@qiin2333 qiin2333 force-pushed the fix/vdd-display-mode-only-vdd-devices branch from 4ca6a24 to 8de6e0f Compare March 13, 2026 16:03
@qiin2333 qiin2333 changed the title fix: VDD模式下仅操作VDD设备的显示设置,修复陈旧GUID导致的模式设置失败 fix(vdd): VDD拓扑范围限定 + 延迟销毁机制,修复首次连接失败和切换应用GUID失效 Mar 13, 2026
dff5a72 的重构中,VDD 模式下 apply_config 不再跳过显示设置,
但 get_current_topology_metadata 返回了整个系统拓扑(物理+VDD),
导致 handle_display_mode_configuration 尝试对所有设备(包括可能不稳定
的物理显示器)设置分辨率/刷新率,引发 'Failed to find device' 错误。

修复:
- get_current_topology_metadata: metadata.current_topology 改为仅包含
  VDD 设备所在的拓扑组,不包含无关的物理显示器
- wait_for_display_stability: 拓扑比较改为 subset 检查,
  避免 VDD 模式下因部分拓扑不匹配导致无意义的 5 秒超时等待
When Cancel is followed by a quick Launch (app switching), instead of
immediately destroying the VDD and restoring topology, defer the entire
restore operation with a grace period (5 seconds timer).

If a new configure_display arrives within the grace period, the timer
is cancelled and the existing VDD is reused — same GUID, same
persistent_data, no topology flicker, no stale device entries.

If the grace period expires without a new session, the full restore
(VDD destruction + topology revert) executes normally.

This benefits ALL display modes (not just no_operation) by eliminating
unnecessary VDD destroy/recreate cycles during app switching.

Also fixes remove_stale_device_entries template to accept std::map
(not just std::unordered_map) matching device_display_mode_map_t.
@qiin2333 qiin2333 force-pushed the fix/vdd-display-mode-only-vdd-devices branch from 8de6e0f to 5c45d92 Compare March 14, 2026 04:22
@ShadowLemoon
Copy link
Collaborator

  1. 医生认为复用id会导致缩放比例失效,我建议加个客户端uuid的检查,如果变动则也走销毁+重建
  2. 不退出应用(暂停会话)时,切换客户端串流有两个分支:
    I. 分辨率已在vdd列表中:不重建,缩放比例和屏幕组合保持不变
    II. 分辨率不在:重建后guid变化,缩放比例和屏幕组合变化
    我建议统一两个分支的行为,统一检查客户端uuid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants