Search code examples
c++uwpwindows-10c++-cxdxgi

How to reduce fullscreen swap chain presentation latency in UWP application?


I have DirectX11 UWP application. I create swap chain using IDXGIFactory2::CreateSwapChainForCoreWindow and usual parameters.

::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

When I try to change it into fullscreen mode by calling ::IDXGISwapChain::SetFullscreenState it fails with DXGI_ERROR_NOT_CURRENTLY_AVAILABLE and I'm getting the following diagnostics:

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: ]

I figured out that I can toggle fullscreen mode by using ApplicationView:

::Windows::UI::ViewManagement::ApplicationView ^ h_view(::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView());
if(h_view->IsFullScreenMode)
{
    h_view->ExitFullScreenMode();
}
else
{
    h_view->TryEnterFullScreenMode();
}

However this method only hides taskbar, hides window frame and maximizes the window. I thought that with flip-model presentation in this case it should be possible to gain low latency advantages of usual fullscreen swap chains, but that doesn't seem two work and swap chain continues to be composited. Composited flip is still used for presentation and presentation lag remains the same ~30ms as in windowed mode. Do I need to disable composition altogether or is there some other method to avoid extra latency applied by composition?


Solution

  • After some experimenting I've managed to find a solution: disabling system overlays in addition to pointer visualization feedback will disable composition in fullscreen mode and presentation will be performed as independent flip. The following code should be added into ::Windows::ApplicationModel::Core::IFrameworkView::SetWindow method implementation:

    ::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;
    

    Note that it does not disable overlays completely, it just shows a little bar first that user needs click to show the corresponding overlay item, such as taskbar.