[PATCH 5/5] dxgi: Implement fullscreen window occlusion detection.
Zhiyi Zhang
zzhang at codeweavers.com
Tue Apr 23 07:59:18 CDT 2019
When Windows detected a fullscreen window occlusion, it will
set the fullscreen window to windowed and return DXGI_STATUS_OCCLUDED
in IDXGISwapChain::Present.
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/dxgi/swapchain.c | 64 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 9f8539fd28..d1df1ad726 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -265,6 +265,42 @@ BOOL dxgi_validate_swapchain_desc(const DXGI_SWAP_CHAIN_DESC1 *desc)
return TRUE;
}
+/* A correct occlusion detection method must consider following scenarios:
+ *
+ * 1. On multiple monitors system. For example, the full-screen is on primary display, any window on
+ * on secondary monitor shouldn't be able to occlude the full-screen window, regardless being foreground or active.
+ * 2. A non-Wine window, e.g., a X window occludes the full-screen window should be detected.
+ *
+ * Current method will incorrectly report occluded status where a window on a secondary monitor becomes foreground,
+ * which shouldn't be too harmful though. The actual implementation on Window probably has help from DWM.
+ *
+ * X11 VisibilityNotify is not useful here. The events doesn't work as expected.
+ */
+static BOOL dxgi_is_window_occluded(HWND hwnd)
+{
+ RECT fullscreen_rect;
+ RECT intersect_rect;
+ RECT window_rect;
+ HWND previous_hwnd;
+
+ if (GetForegroundWindow() != hwnd)
+ return TRUE;
+
+ /* Check if windows with higher z-order intersect with the full-screen window */
+ GetWindowRect(hwnd, &fullscreen_rect);
+ previous_hwnd = GetWindow(hwnd, GW_HWNDPREV);
+ while (previous_hwnd)
+ {
+ GetWindowRect(previous_hwnd, &window_rect);
+ if (IntersectRect(&intersect_rect, &window_rect, &fullscreen_rect))
+ return TRUE;
+
+ previous_hwnd = GetWindow(previous_hwnd, GW_HWNDPREV);
+ }
+
+ return FALSE;
+}
+
static HRESULT dxgi_get_output_from_window(IDXGIAdapter *adapter, HWND window, IDXGIOutput **dxgi_output)
{
DXGI_OUTPUT_DESC desc;
@@ -456,12 +492,27 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *ifac
static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain,
unsigned int sync_interval, unsigned int flags)
{
+ BOOL fullscreen = FALSE;
+ HRESULT hr;
+ HWND hwnd;
+
if (sync_interval > 4)
{
WARN("Invalid sync interval %u.\n", sync_interval);
return DXGI_ERROR_INVALID_CALL;
}
+ hr = IDXGISwapChain1_GetFullscreenState(&swapchain->IDXGISwapChain1_iface, &fullscreen, NULL);
+ if (SUCCEEDED(hr) && fullscreen)
+ {
+ hr = IDXGISwapChain1_GetHwnd(&swapchain->IDXGISwapChain1_iface, &hwnd);
+ if (SUCCEEDED(hr) && dxgi_is_window_occluded(hwnd))
+ {
+ IDXGISwapChain1_SetFullscreenState(&swapchain->IDXGISwapChain1_iface, FALSE, NULL);
+ return DXGI_STATUS_OCCLUDED;
+ }
+ }
+
if (flags & ~DXGI_PRESENT_TEST)
FIXME("Unimplemented flags %#x.\n", flags);
if (flags & DXGI_PRESENT_TEST)
@@ -2118,8 +2169,10 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
unsigned int sync_interval, unsigned int flags)
{
+ BOOL fullscreen = FALSE;
VkQueue vk_queue;
VkResult vr;
+ HWND hwnd;
HRESULT hr;
if (sync_interval > 4)
@@ -2128,6 +2181,17 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
return DXGI_ERROR_INVALID_CALL;
}
+ hr = IDXGISwapChain3_GetFullscreenState(&swapchain->IDXGISwapChain3_iface, &fullscreen, NULL);
+ if (SUCCEEDED(hr) && fullscreen)
+ {
+ hr = IDXGISwapChain3_GetHwnd(&swapchain->IDXGISwapChain3_iface, &hwnd);
+ if (SUCCEEDED(hr) && dxgi_is_window_occluded(hwnd))
+ {
+ IDXGISwapChain3_SetFullscreenState(&swapchain->IDXGISwapChain3_iface, FALSE, NULL);
+ return DXGI_STATUS_OCCLUDED;
+ }
+ }
+
if (flags & ~DXGI_PRESENT_TEST)
FIXME("Unimplemented flags %#x.\n", flags);
if (flags & DXGI_PRESENT_TEST)
--
2.20.1
More information about the wine-devel
mailing list