cat*_*ier 6 directx-11 dxgi sharpdx
我只是偶然发现了这个令人烦恼的行为,同时在示例程序上添加了全屏支持.
创建一个全屏窗口可以工作,但只要我在包含我的全屏窗口的输出上移动任何窗口(从另一个应用程序),它就会自动切换回窗口.
有没有办法防止这种行为(所以全屏窗口不会回到窗口)?
作为参考,这是一个小的独立示例(因此可以轻松复制问题).
如果这很有用,我也在Windows 8.1上运行.
我已经尝试更改WindowAssociationFlags和SwapChainFlags,两者都没有成功,与使用FlipSequential而不是Discard相同
SharpDX.DXGI.Factory2 factory = new SharpDX.DXGI.Factory2();
SharpDX.DXGI.Adapter adapter = factory.GetAdapter(0);
var renderForm1 = new RenderForm("Form 1");
factory.MakeWindowAssociation(renderForm1.Handle, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll);
Device device = new Device(adapter, DeviceCreationFlags.BgraSupport);
SharpDX.DXGI.SwapChainDescription sd = new SharpDX.DXGI.SwapChainDescription()
{
BufferCount = 2,
ModeDescription = new SharpDX.DXGI.ModeDescription(0, 0, new SharpDX.DXGI.Rational(50, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = renderForm1.Handle,
SampleDescription = new SharpDX.DXGI.SampleDescription(1,0),
SwapEffect = SharpDX.DXGI.SwapEffect.Discard,
Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
Flags = SharpDX.DXGI.SwapChainFlags.None
};
var swapChain1 = new SharpDX.DXGI.SwapChain(factory, device, sd);
renderForm1.Left = 1922; //Just hardcoded here to move window to second screen
renderForm1.Width = 1920;
renderForm1.Height = 1080;
renderForm1.FormBorderStyle = FormBorderStyle.None;
swapChain1.SetFullscreenState(true, null);
swapChain1.ResizeBuffers(2, 1920, 1080, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.SwapChainFlags.AllowModeSwitch);
var resource = Texture2D.FromSwapChain<Texture2D>(swapChain1, 0);
var renderView = new RenderTargetView(device, resource);
RenderLoop.Run(renderForm1, () =>
{
device.ImmediateContext.ClearRenderTargetView(renderView, new SharpDX.Color4(1, 0, 0, 1));
swapChain1.Present(1, SharpDX.DXGI.PresentFlags.None);
});
Run Code Online (Sandbox Code Playgroud)
编辑:我也尝试了一个c ++示例(刚刚从Microsoft获取DirectX11基础教程并添加了全屏切换),这导致了相同的行为,因此这不是SharpDX的具体问题.
我查看了消息循环,一旦发生这种情况,首先将全屏模式更改回窗口,然后收到WM_DISPLAYCHANGE消息.
这听起来像是预期的行为。如果你有一个全屏幕“独占”模式swapchain和相关的窗口失去焦点时,系统自动切换应用了全屏模式返回到窗口模式的设计。
使用单个监视器,只要您将应用程序的窗口大小调整为填满显示屏,它就可以正常工作。用户不能使用鼠标来改变窗口的焦点,它需要像 ALT+TAB 这样的东西来切换焦点。
使用多个显示器,这是一个真正的问题。如果您单击另一个显示器上的另一个窗口,您的应用将失去焦点并再次关闭全屏模式。还有一些限制会阻止您在多台显示器上设置全屏“独占”模式。
此外,在 Windows Vista 或更高版本上,“独占”模式的概念是一种幻觉:无论如何,GPU 始终是共享的。无论是全屏还是窗口交换链,“焦点”应用程序都具有优先权。
对于 Windows 桌面应用程序,您可以选择三种全屏风格体验:
IsWindowed = false。WS_POPUP)。在这里你有IsWindowed = true,你应该确保设置DXGI_MWA_NO_ALT_ENTER避免让DXGI试图带你使用1的情况。IsWindowed = true并将无边框窗口的大小调整为与屏幕匹配,但您可以将显示模式更改为系统默认设置以外的其他模式。这通常被称为“假全屏”。每当您退出应用程序时,显示模式就会变回。1 具有我们刚刚描述的多任务处理和专注的所有问题。2 和 3 允许系统通知和其他弹出窗口显示在游戏中,而不是强制模式切换。2 和 3 在多显示器设置中也能更好地工作,您可以在一个显示器上玩游戏并在另一台显示器上使用其他应用程序。对于多任务处理,大多数人更喜欢带有框架边框的经典窗口样式。
全屏模式的 Windows Store UWP 概念基本上类似于上面的 2。您无法使用 UWP 更改显示模式。
调试全屏设置非常具有挑战性。使用多个监视器,2 和 3 可以在另一个屏幕上与您的调试器一起使用。对于真正的全屏独占模式,实际上唯一的选择是使用另一台 PC 的远程调试。
1 和 3 的另一个问题是,您可以将显示模式设置为不与显示同步的内容,从而使用户的系统没有 UI 且无法退出。理想情况下,使用正确的驱动程序设置,DXGI 枚举列表不包含不受支持的模式,但需要注意。出于这个原因,用于选择显示模式的 UI 应该有一个超时,并且如果显示模式在将来的某个时间点无法同步,您应该确保有一种合理的方法可以使用键盘中止应用程序。像我们在上面 2 中所做的那样使用现有的显示模式始终是最安全的选择。
使用上面的全屏独占模式 (1) 的主要原因是尝试获取后台缓冲区/前台缓冲区的“翻转”而不是“块”。对于大多数现代系统,这是一个可以忽略不计的性能差异。另一个痛苦的原因是 SLI/Crossfire 多 GPU 渲染到单个显示器。要真正使该场景发挥作用,还需要进行许多其他优化,而且它非常小众。您应该查找供应商优化指南以了解详细信息。
大多数现代游戏默认使用假全屏而不是全屏“独占”模式。它们提供了使用真正窗口模式的能力,因为许多用户希望在玩游戏时能够同时处理多项任务(例如在线查找提示、使用 IM 或外部语音聊天等)。想要支持 SLI/Crossfire 高性能游戏的 AAA Windows 桌面游戏将提供全屏“独占”模式,但这需要一些工作才能完全运行,并且需要做的不仅仅是一些 DXGI 代码。
请参阅DXGI 概述和DirectX 图形基础架构 (DXGI):最佳实践