diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp index dc1c556dd7d4..50a3b10bc92e 100644 --- a/src/dxgi/dxgi_factory.cpp +++ b/src/dxgi/dxgi_factory.cpp @@ -302,7 +302,7 @@ namespace dxvk { return hr; } - frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc); + frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc, pDevice); } else { Logger::err("DXGI: CreateSwapChainForHwnd: Unsupported device type"); return DXGI_ERROR_UNSUPPORTED; diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 68247306582a..5f97684dfeeb 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -4,6 +4,8 @@ #include "../util/util_misc.h" +#include + namespace dxvk { DxgiSwapChain::DxgiSwapChain( @@ -11,14 +13,17 @@ namespace dxvk { IDXGIVkSwapChain* pPresenter, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, - const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc) + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, + IUnknown* pDevice) : m_factory (pFactory), m_window (hWnd), m_desc (*pDesc), m_descFs (*pFullscreenDesc), m_presentId (0u), m_presenter (pPresenter), - m_monitor (wsi::getWindowMonitor(m_window)) { + m_monitor (wsi::getWindowMonitor(m_window)), + m_is_d3d12(SUCCEEDED(pDevice->QueryInterface(__uuidof(ID3D12CommandQueue), reinterpret_cast(&Com())))) { + if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast(&m_adapter)))) throw DxvkError("DXGI: Failed to get adapter for present device"); @@ -243,7 +248,9 @@ namespace dxvk { BOOL* pFullscreen, IDXGIOutput** ppTarget) { HRESULT hr = S_OK; - + + if (!m_is_d3d12 && !m_descFs.Windowed && wsi::isOccluded(m_window)) + SetFullscreenState(FALSE, nullptr); if (pFullscreen != nullptr) *pFullscreen = !m_descFs.Windowed; @@ -325,6 +332,10 @@ namespace dxvk { if (SyncInterval > 4) return DXGI_ERROR_INVALID_CALL; + if ((m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD || m_desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL) && wsi::isMinimized(m_window)) + return DXGI_STATUS_OCCLUDED; + bool occluded = !m_descFs.Windowed && wsi::isOccluded(m_window) && !wsi::isMinimized(m_window); + auto options = m_factory->GetOptions(); if (options->syncInterval >= 0) @@ -342,7 +353,7 @@ namespace dxvk { } if (PresentFlags & DXGI_PRESENT_TEST) - return hr; + return hr == S_OK && occluded ? DXGI_STATUS_OCCLUDED : hr; if (hr == S_OK) { @@ -365,6 +376,11 @@ namespace dxvk { monitorData->FrameStats.PresentRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod); ReleaseMonitorData(); } + if (occluded) { + if (!(PresentFlags & DXGI_PRESENT_TEST)) + SetFullscreenState(FALSE, nullptr); + hr = DXGI_STATUS_OCCLUDED; + } } return hr; diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index 4bdad9d0f574..c6e7da71a9a8 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -31,7 +31,8 @@ namespace dxvk { IDXGIVkSwapChain* pPresenter, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, - const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc); + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, + IUnknown* pDevice); ~DxgiSwapChain(); @@ -197,6 +198,7 @@ namespace dxvk { double m_frameRateOption = 0.0; double m_frameRateRefresh = 0.0; double m_frameRateLimit = 0.0; + bool m_is_d3d12; DXGI_COLOR_SPACE_TYPE m_colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; diff --git a/src/wsi/glfw/wsi_platform_glfw.h b/src/wsi/glfw/wsi_platform_glfw.h index 849ce4f5fe69..ee6261baee6f 100644 --- a/src/wsi/glfw/wsi_platform_glfw.h +++ b/src/wsi/glfw/wsi_platform_glfw.h @@ -95,6 +95,10 @@ namespace dxvk::wsi { virtual bool isWindow(HWND hWindow); + virtual bool isMinimized(HWND hWindow); + + virtual bool isOccluded(HWND hWindow); + virtual void updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/glfw/wsi_window_glfw.cpp b/src/wsi/glfw/wsi_window_glfw.cpp index f763e759a5a5..357c427d2419 100644 --- a/src/wsi/glfw/wsi_window_glfw.cpp +++ b/src/wsi/glfw/wsi_window_glfw.cpp @@ -126,6 +126,18 @@ namespace dxvk::wsi { return window != nullptr; } + + bool GlfwWsiDriver::isMinimized(HWND hWindow) { + GLFWwindow* window = fromHwnd(hWindow); + return glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0; + } + + + bool GlfwWsiDriver::isOccluded(HWND hWindow) { + return false; + } + + void GlfwWsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/sdl2/wsi_platform_sdl2.h b/src/wsi/sdl2/wsi_platform_sdl2.h index 1a6ac8aad8fc..bc29812a27b7 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.h +++ b/src/wsi/sdl2/wsi_platform_sdl2.h @@ -93,6 +93,10 @@ namespace dxvk::wsi { virtual bool isWindow(HWND hWindow); + virtual bool isMinimized(HWND hWindow); + + virtual bool isOccluded(HWND hWindow); + virtual void updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/sdl2/wsi_platform_sdl2_funcs.h b/src/wsi/sdl2/wsi_platform_sdl2_funcs.h index 3da94922dc1a..4396a6bb6b5f 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2_funcs.h +++ b/src/wsi/sdl2/wsi_platform_sdl2_funcs.h @@ -8,6 +8,7 @@ SDL_PROC(int, SDL_GetNumVideoDisplays, (void)) SDL_PROC(int, SDL_GetWindowDisplayIndex, (SDL_Window*)) SDL_PROC(int, SDL_SetWindowDisplayMode, (SDL_Window*, const SDL_DisplayMode*)) SDL_PROC(int, SDL_SetWindowFullscreen, (SDL_Window*, Uint32)) +SDL_PROC(SDL_WindowFlags, SDL_GetWindowFlags, (SDL_Window *)) SDL_PROC(void, SDL_GetWindowSize, (SDL_Window*, int*, int*)) SDL_PROC(void, SDL_SetWindowSize, (SDL_Window*, int, int)) SDL_PROC(SDL_bool, SDL_Vulkan_CreateSurface, (SDL_Window*, VkInstance, VkSurfaceKHR*)) diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index 33084dc34b54..90b6107bc0ff 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -136,6 +136,17 @@ namespace dxvk::wsi { } + bool Sdl2WsiDriver::isMinimized(HWND hWindow) { + SDL_Window* window = fromHwnd(hWindow); + return (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0; + } + + + bool Sdl2WsiDriver::isOccluded(HWND hWindow) { + return false; + } + + void Sdl2WsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/win32/wsi_platform_win32.h b/src/wsi/win32/wsi_platform_win32.h index 1364baf15360..2a47e4f2fcb4 100644 --- a/src/wsi/win32/wsi_platform_win32.h +++ b/src/wsi/win32/wsi_platform_win32.h @@ -77,6 +77,10 @@ namespace dxvk::wsi { virtual bool isWindow(HWND hWindow); + virtual bool isMinimized(HWND hWindow); + + virtual bool isOccluded(HWND hWindow); + virtual void updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp index 894da8e7b691..4deb039ef2ce 100644 --- a/src/wsi/win32/wsi_window_win32.cpp +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -254,6 +254,16 @@ namespace dxvk::wsi { } + bool Win32WsiDriver::isMinimized(HWND hWindow) { + return (::GetWindowLongW(hWindow, GWL_STYLE) & WS_MINIMIZE) != 0; + } + + + bool Win32WsiDriver::isOccluded(HWND hWindow) { + return ::GetForegroundWindow() != hWindow; + } + + void Win32WsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/wsi_platform.cpp b/src/wsi/wsi_platform.cpp index 3245eb13e718..76e72f0225e2 100644 --- a/src/wsi/wsi_platform.cpp +++ b/src/wsi/wsi_platform.cpp @@ -112,6 +112,14 @@ namespace dxvk::wsi { return s_driver->isWindow(hWindow); } + bool isMinimized(HWND hWindow) { + return s_driver->isMinimized(hWindow); + } + + bool isOccluded(HWND hWindow) { + return s_driver->isOccluded(hWindow); + } + void updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index 8c37bc94927a..9f891cfc0d69 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -80,6 +80,10 @@ namespace dxvk::wsi { virtual bool isWindow(HWND hWindow) = 0; + virtual bool isMinimized(HWND hWindow); + + virtual bool isOccluded(HWND hWindow); + virtual void updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h index ceb149238e80..ed0f87d88800 100644 --- a/src/wsi/wsi_window.h +++ b/src/wsi/wsi_window.h @@ -117,6 +117,22 @@ namespace dxvk::wsi { */ bool isWindow(HWND hWindow); + /** + * \brief Is window minimized? + * + * \param [in] hWindow The window + * \returns Is window minimized? + */ + bool isMinimized(HWND hWindow); + + /** + * \brief Is window occluded? + * + * \param [in] hWindow The window + * \returns Is window occluded? + */ + bool isOccluded(HWND hWindow); + /** * \brief Update a fullscreen window's position/size *