如何减少 UWP 应用程序中的全屏交换链显示延迟?
How to reduce fullscreen swap chain presentation latency in UWP application?
我有 DirectX11 UWP 应用程序。我使用 IDXGIFactory2::CreateSwapChainForCoreWindow
和常用参数创建交换链。
::DXGI_SWAP_CHAIN_DESC1 desc{};
desc.Width = back_buffer_width;
desc.Height = back_buffer_height;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
desc.Scaling = DXGI_SCALING_NONE;
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
::Microsoft::WRL::ComPtr< ::IDXGISwapChain1 > p_swap_chain;
Validate_OkResult
(
p_dxgi_factory->CreateSwapChainForCoreWindow
(
p_d3d_device.Get()
, reinterpret_cast< ::IUnknown * >(h_window) // passing ::Windows::UI::Core::CoreWindow ^
, ::std::addressof(desc)
, nullptr
, &p_swap_chain
)
);
Validate_OkResult(p_swap_chain->SetMaximumFrameLatency(1)); // 1 is minimum allowed value
当我尝试通过调用 ::IDXGISwapChain::SetFullscreenState
将其更改为全屏模式时,它失败并显示 DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
并且我得到以下诊断信息:
DXGI ERROR: IDXGISwapChain::SetFullscreenState: Core Window SwapChains cannot transition to fullscreen, as they are considered perpetually windowed. [ MISCELLANEOUS ERROR #163: ]
DXGI ERROR: IDXGISwapChain::SetFullscreenState: For modern applications, fullscreen is not available. All swapchains must be windowed. [ MISCELLANEOUS ERROR #206: ]
我发现我可以使用 ApplicationView
:
切换全屏模式
::Windows::UI::ViewManagement::ApplicationView ^ h_view(::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView());
if(h_view->IsFullScreenMode)
{
h_view->ExitFullScreenMode();
}
else
{
h_view->TryEnterFullScreenMode();
}
然而,此方法仅隐藏任务栏,隐藏 window 框架并最大化 window。我认为在这种情况下使用翻转模型演示应该可以获得通常的全屏交换链的低延迟优势,但这似乎不是两个工作并且交换链继续被合成。复合翻转仍用于演示,演示延迟与 windowed 模式下保持相同 ~30ms。我是否需要完全禁用组合,或者是否有其他方法可以避免组合应用的额外延迟?
经过一些试验,我设法找到了一个解决方案:除了指针可视化反馈之外,禁用系统覆盖将禁用全屏模式下的合成,并且演示将作为独立翻转执行。应将以下代码添加到 ::Windows::ApplicationModel::Core::IFrameworkView::SetWindow
方法实现中:
::Windows::UI::Input::PointerVisualizationSettings ^ h_visualization_settings{::Windows::UI::Input::PointerVisualizationSettings::GetForCurrentView()};
h_visualization_settings->IsContactFeedbackEnabled = false;
h_visualization_settings->IsBarrelButtonFeedbackEnabled = false;
::Windows::UI::ViewManagement::ApplicationView ^ h_view{::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()};
h_view->FullScreenSystemOverlayMode = ::Windows::UI::ViewManagement::FullScreenSystemOverlayMode::Minimal;
请注意,它并没有完全禁用覆盖,它只是先显示一个小条,用户需要单击以显示相应的覆盖项,例如任务栏。
我有 DirectX11 UWP 应用程序。我使用 IDXGIFactory2::CreateSwapChainForCoreWindow
和常用参数创建交换链。
::DXGI_SWAP_CHAIN_DESC1 desc{};
desc.Width = back_buffer_width;
desc.Height = back_buffer_height;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
desc.Scaling = DXGI_SCALING_NONE;
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
::Microsoft::WRL::ComPtr< ::IDXGISwapChain1 > p_swap_chain;
Validate_OkResult
(
p_dxgi_factory->CreateSwapChainForCoreWindow
(
p_d3d_device.Get()
, reinterpret_cast< ::IUnknown * >(h_window) // passing ::Windows::UI::Core::CoreWindow ^
, ::std::addressof(desc)
, nullptr
, &p_swap_chain
)
);
Validate_OkResult(p_swap_chain->SetMaximumFrameLatency(1)); // 1 is minimum allowed value
当我尝试通过调用 ::IDXGISwapChain::SetFullscreenState
将其更改为全屏模式时,它失败并显示 DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
并且我得到以下诊断信息:
DXGI ERROR: IDXGISwapChain::SetFullscreenState: Core Window SwapChains cannot transition to fullscreen, as they are considered perpetually windowed. [ MISCELLANEOUS ERROR #163: ]
DXGI ERROR: IDXGISwapChain::SetFullscreenState: For modern applications, fullscreen is not available. All swapchains must be windowed. [ MISCELLANEOUS ERROR #206: ]
我发现我可以使用 ApplicationView
:
::Windows::UI::ViewManagement::ApplicationView ^ h_view(::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView());
if(h_view->IsFullScreenMode)
{
h_view->ExitFullScreenMode();
}
else
{
h_view->TryEnterFullScreenMode();
}
然而,此方法仅隐藏任务栏,隐藏 window 框架并最大化 window。我认为在这种情况下使用翻转模型演示应该可以获得通常的全屏交换链的低延迟优势,但这似乎不是两个工作并且交换链继续被合成。复合翻转仍用于演示,演示延迟与 windowed 模式下保持相同 ~30ms。我是否需要完全禁用组合,或者是否有其他方法可以避免组合应用的额外延迟?
经过一些试验,我设法找到了一个解决方案:除了指针可视化反馈之外,禁用系统覆盖将禁用全屏模式下的合成,并且演示将作为独立翻转执行。应将以下代码添加到 ::Windows::ApplicationModel::Core::IFrameworkView::SetWindow
方法实现中:
::Windows::UI::Input::PointerVisualizationSettings ^ h_visualization_settings{::Windows::UI::Input::PointerVisualizationSettings::GetForCurrentView()};
h_visualization_settings->IsContactFeedbackEnabled = false;
h_visualization_settings->IsBarrelButtonFeedbackEnabled = false;
::Windows::UI::ViewManagement::ApplicationView ^ h_view{::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()};
h_view->FullScreenSystemOverlayMode = ::Windows::UI::ViewManagement::FullScreenSystemOverlayMode::Minimal;
请注意,它并没有完全禁用覆盖,它只是先显示一个小条,用户需要单击以显示相应的覆盖项,例如任务栏。