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

6
DXGI的MSDN页面介绍了如何处理与桌面分辨率不同的全屏分辨率。其中提到,在调用IDXGISwapChain::SetFullscreenState()之前,需要调用IDXGISwapChain::ResizeTargets()来防止闪烁等问题。
然而,它并未说明如何处理Alt-Enter,该操作会在程序有机会调用IDXGISwapChain::ResizeTargets()之前调用IDXGISwapChain::SetFullscreenState()。如果在收到WM_SIZE消息时调用后者,可能会导致无限循环发送WM_SIZE消息。如何确保在按下alt-enter或alt-tab时先调用后者,以及在一般情况下无缝切换模式呢?
2个回答

10
这将非常棘手...正确处理的方法是使用IDXGIFactory::MakeWindowAssociation,据我所知,没有人成功使用过。您可能仍然想尝试一下。
“正确”的答案是手动处理Alt+Enter。因此,使用MakeWindowAssociation禁用Alt+Enter并亲自动手。首先,没有必要捕获WM_SIZE。相反,监听WM_ENTERSIZEMOVEWM_CAPTURECHANGEDWM_WINDOWPOSCHANGEDWM_EXITSIZEMOVE。这将避免您不必处理WM_SIZE但仍能获取所有相关的窗口调整大小事件。(当您这样做时,请阅读这个问题:WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE - when using menu, not always paired)
好吧,假设一切都顺利,对于Alt+Enter,您需要执行以下操作:使用IDXGISwapChain::SetFullscreenState将交换链设置为全屏,然后重新调整交换链(IDXGISwapChain::ResizeBuffers)。默认情况下,您将获得一个尽可能接近窗口当前分辨率的交换链。正确的做法是先枚举全屏分辨率,然后在全屏模式下强制使用您想要的分辨率。这听起来很丑陋,但似乎是解决问题最稳定的方法。
一般来说,真正的独占全屏模式并不值得麻烦,因为当有人按Alt+Tab时,您总会出现闪烁(如果发生模式切换,您无法避免它,因为屏幕本身必须重新调整)。更好的解决方案是使用全屏无边框窗口。您只需创建一个没有任何装饰的窗口类,使其全屏,放置在覆盖整个屏幕的位置,然后就可以愉快地工作了。然后您就不必担心Alt+Enter和Alt+Tab。这还允许人们在第二个屏幕上继续工作而不会闪烁。从性能上看,这相当不错(大多数新游戏都支持这种“无边框全屏”)。

也许有一种能够正确解决所有问题的完美方案,但我还没有见过。如果有更加清晰/优雅的解决方案,我会非常想听听。不过,“无边框全屏”似乎是当前的标准,据我所知,Unity 5只允许在Direct3D 11下使用“无边框全屏”。


1
只是一个更新 - 我只用 WM_SIZE 就实现了我想要的。虽然有点 hack,但只有一行并且不会真正造成问题。当调用 WM_SIZE 时,我会检查渲染目标视图是否存在,然后再调整缓冲区。这样,我在窗口创建时就不会遇到空指针错误了。除此之外,其他都按照您说的进行了。 - NmdMystery
你是如何处理ALT+Enter的呢? 你说要在MakeWindowAssociation中禁用ALT+ENTER,但ALT+ENTER并不会触发你答案中提到的任何消息。 - Raildex
对于键盘输入,请使用“Normal”内容,即WM_*KEYDOWN或原始输入。它不需要特殊的消息。 - Anteru
“独占全屏模式不值得麻烦。”但对于玩家来说,它是值得的。对于任何快节奏的游戏来说,这是必须的:您不希望桌面窗口管理器强制在玩家身上使用三倍缓冲的垂直同步,并且无法切换到真正的全屏模式。对于需要快速操作的任何应用程序,窗口化或无边界窗口化都是可憎的。不要让你的玩家基础受到影响。如果他们需要在游戏中做出反应或快速完成某些操作,请始终添加真正的全屏支持。 - KulaGGin
“FLIP”演示模型允许您在运行无边框窗口模式时绕过DWM,因此您不会从独占中获得任何好处。唯一需要担心独占的原因是当您需要切换HDR并且不能依赖桌面处于HDR模式时。 - Anteru

3
我想在这个问题上补充一些更新 - 我编写了一个小型窗口库,我相信它可以很好地处理DXGI - 没有调试消息,没有错误消息,并且一切都表现出预期的行为,至少在我的Windows环境中是如此。解决这个问题的完整方案太过复杂,无法在单个答案中解释,因为它需要大量精确放置的方法调用(DXGI变得非常,非常刻板)。但如果任何人想查看它,我已经将我的代码上传到Github。具体来说,这个文件这个文件就是您需要查看的文件 - 后者是前者的聚合对象。

请注意,我已禁用了ALT+ENTER,转而使用F11,但功能完全相同。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接