正确处理Alt-Enter / Alt-Tab全屏分辨率

DXGI上的MSDN页面提供了有关如何处理与桌面分辨率不同的全屏分辨率的说明。 它说调用IDXGISwapChain::ResizeTargets()之前调用IDXGISwapChain::SetFullscreenState()以防止闪烁,等等。

它没有说如何处理Alt-Enter,它在程序被给予对IDXGISwapChain::ResizeTargets()的调用之前调用IDXGISwapChain::ResizeTargets() 。 如果在WM_SIZE消息上调用后一种方法,则会发送另一个WM_SIZE消息,可能导致无限循环。 我怎样才能确保后者将被调用之前,当按Alt或Alt-Tab被按下,模式切换一般无痛苦地发生?

这将是非常棘手的…正确的方式应该如何处理是IDXGIFactory::MakeWindowAssociation ,据我所知,没有人成功地使用。 无论如何,你可能想尝试一下。

“正确的”答案是手动处理Alt + Enter。 所以,使用MakeWindowAssociation禁用Alt + Enter,让你的手变脏。 首先,不需要捕获WM_SIZE 。 相反,听取WM_ENTERSIZEMOVEWM_CAPTURECHANGEDWM_WINDOWPOSCHANGEDWM_EXITSIZEMOVE 。 这将阻止您必须处理WM_SIZE并仍然获取所有相关的窗口大小调整事件。 (当这样做时,请阅读以下问题: WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE – 使用菜单时,不总是配对 )

好吧,假设一切正常,对于Alt + Enter,您必须执行以下操作:使用IDXGISwapChain::SetFullscreenState将交换链设置为全屏,然后调整交换链( IDXGISwapChain::ResizeBuffers )的大小。 默认情况下,您将获得一个交换链,它在调整大小之前尽可能接近您的窗口的当前分辨率。 正确的做法是首先枚举全屏幕分辨率,并在全屏时强制显示您想要的分辨率。 这听起来很丑,但似乎是解决问题的最可靠的方法。

一般来说,真正的独家全屏模式是不值得的,因为当有人进入Alt + Tab时,你将总是闪烁(如果模式切换发生,你不能避免它,因为屏幕本身将不得不重新调整)。更好的解决方案是使用全屏无边界窗口。 您只需创建一个没有任何装饰的窗口类,使其全屏,将其放置在整个屏幕上,并完成它。 那么你不必担心Alt + Enter和Alt + Tab。 它也允许人们继续在没有闪烁的第二个屏幕上工作。 性能方面,这是相当ok'ish(大多数新游戏支持“无边界全屏”)。

可能有一颗银弹,它正确地解决了这一切,但我还没有看到它。 如果有更清洁/更好的解决方案,我会非常好奇。 “无边界全屏”似乎是目前的标准,但是,IIRC,Unity 5将只允许Direct3D 11的“无边界全屏”。

我只是想在这个问题上添加一个更新 – 我已经写了一个小窗口库,我相信它可以很好地处理DXGI – 至少在我的Windows环境中,没有调试消息,没有错误消息,并且所有的行为都像预期的那样。 这个问题的完整解决方案太复杂,无法在一个单一的答案中解释,因为它需要大量精确的方法调用(DXGI实际上是非常严格的),但是我有我的代码在github上,如果有人想看看它。 具体来说, 这个文件和这个文件是你想要看的 – 后者是前者的聚合对象。

请注意,我已经禁用了ALT-ENTER而选择了F11,但功能完全相同。

如果你想使用这个库,顺便说一句,我把它作为免费软件发布,并且很快就会提供文档。