[PATCH v4] gdi32/tests: Add D3DKMTCheckOcclusion tests.

Zhiyi Zhang zzhang at codeweavers.com
Fri May 24 22:55:07 CDT 2019


Mostly to show that D3DKMTCheckOcclusion is mainly composed of
ownership checks rather than actually window occlusion. Also
composition status doesn't affect its behavior despite MSDN
say so.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
v4: Rebase. Minor cleanup. Supersede 165395

 dlls/gdi32/tests/driver.c | 195 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 195 insertions(+)

diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index d8ae0f89ce..3b8953b4c3 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -27,12 +27,14 @@
 #include "wingdi.h"
 #include "winuser.h"
 #include "winternl.h"
+#include "dwmapi.h"
 #include "ddk/d3dkmthk.h"
 
 #include "wine/test.h"
 
 static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
 
+static NTSTATUS (WINAPI *pD3DKMTCheckOcclusion)(const D3DKMT_CHECKOCCLUSION *);
 static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *);
 static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
 static NTSTATUS (WINAPI *pD3DKMTCreateDevice)(D3DKMT_CREATEDEVICE *);
@@ -40,6 +42,7 @@ static NTSTATUS (WINAPI *pD3DKMTDestroyDevice)(const D3DKMT_DESTROYDEVICE *);
 static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
 static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC *);
 static NTSTATUS (WINAPI *pD3DKMTSetVidPnSourceOwner)(const D3DKMT_SETVIDPNSOURCEOWNER *);
+static HRESULT  (WINAPI *pDwmEnableComposition)(UINT);
 
 static void test_D3DKMTOpenAdapterFromGdiDisplayName(void)
 {
@@ -606,10 +609,196 @@ static void test_D3DKMTSetVidPnSourceOwner(void)
     ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
 }
 
+static void test_D3DKMTCheckOcclusion(void)
+{
+    DISPLAY_DEVICEW display_device = {sizeof(display_device)};
+    D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+    D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_owner_desc;
+    D3DKMT_SETVIDPNSOURCEOWNER set_owner_desc;
+    D3DKMT_DESTROYDEVICE destroy_device_desc;
+    D3DKMT_VIDPNSOURCEOWNER_TYPE owner_type;
+    D3DKMT_CLOSEADAPTER close_adapter_desc;
+    D3DKMT_CREATEDEVICE create_device_desc;
+    D3DKMT_CHECKOCCLUSION occlusion_desc;
+    NTSTATUS expected_occlusion, status;
+    INT i, adapter_count = 0;
+    HWND hwnd, hwnd2;
+    HRESULT hr;
+
+    if (!pD3DKMTCheckOcclusion || pD3DKMTCheckOcclusion(NULL) == STATUS_PROCEDURE_NOT_FOUND)
+    {
+        skip("D3DKMTCheckOcclusion() is unavailable.\n");
+        return;
+    }
+
+    /* NULL parameter check */
+    status = pD3DKMTCheckOcclusion(NULL);
+    ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+    occlusion_desc.hWnd = NULL;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+    hwnd = CreateWindowA("static", "static1", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 200, 200, 0, 0, 0, 0);
+    ok(hwnd != NULL, "Failed to create window.\n");
+
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    /* Minimized state doesn't affect D3DKMTCheckOcclusion */
+    ShowWindow(hwnd, SW_MINIMIZE);
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+    ShowWindow(hwnd, SW_SHOWNORMAL);
+
+    /* Invisible state doesn't affect D3DKMTCheckOcclusion */
+    ShowWindow(hwnd, SW_HIDE);
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+    ShowWindow(hwnd, SW_SHOW);
+
+    /* hwnd2 covers hwnd */
+    hwnd2 = CreateWindowA("static", "static2", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, 0);
+    ok(hwnd2 != NULL, "Failed to create window.\n");
+
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    occlusion_desc.hWnd = hwnd2;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    /* Composition doesn't affect D3DKMTCheckOcclusion */
+    if (pDwmEnableComposition)
+    {
+        hr = pDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
+        ok(hr == S_OK, "Failed to disable composition.\n");
+
+        occlusion_desc.hWnd = hwnd;
+        status = pD3DKMTCheckOcclusion(&occlusion_desc);
+        /* This result means that D3DKMTCheckOcclusion doesn't check composition status despite MSDN says it will */
+        ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+        occlusion_desc.hWnd = hwnd2;
+        status = pD3DKMTCheckOcclusion(&occlusion_desc);
+        ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+        ShowWindow(hwnd, SW_MINIMIZE);
+        occlusion_desc.hWnd = hwnd;
+        status = pD3DKMTCheckOcclusion(&occlusion_desc);
+        ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+        ShowWindow(hwnd, SW_SHOWNORMAL);
+
+        ShowWindow(hwnd, SW_HIDE);
+        occlusion_desc.hWnd = hwnd;
+        status = pD3DKMTCheckOcclusion(&occlusion_desc);
+        ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+        ShowWindow(hwnd, SW_SHOW);
+
+        hr = pDwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
+        ok(hr == S_OK, "Failed to enable composition.\n");
+    }
+    else
+        skip("Skip testing composition.\n");
+
+    lstrcpyW(open_adapter_gdi_desc.DeviceName, display1W);
+    status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    memset(&create_device_desc, 0, sizeof(create_device_desc));
+    create_device_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    status = pD3DKMTCreateDevice(&create_device_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    check_owner_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    check_owner_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+    /* D3DKMTCheckVidPnExclusiveOwnership gets STATUS_GRAPHICS_PRESENT_UNOCCLUDED sometimes and with some delay,
+     * it will always return STATUS_SUCCESS. So there are some timing issues here. */
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected return code %#x.\n", status);
+
+    /* Test D3DKMTCheckOcclusion relationship with video present source owner */
+    set_owner_desc.hDevice = create_device_desc.hDevice;
+    owner_type = D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE;
+    set_owner_desc.pType = &owner_type;
+    set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+    set_owner_desc.VidPnSourceCount = 1;
+    status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    for (i = 0; EnumDisplayDevicesW(NULL, i, &display_device, 0); ++i)
+    {
+        if ((display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+            adapter_count++;
+    }
+    /* STATUS_GRAPHICS_PRESENT_OCCLUDED on single monitor system. STATUS_SUCCESS on multiple monitor system. */
+    expected_occlusion = adapter_count > 1 ? STATUS_SUCCESS : STATUS_GRAPHICS_PRESENT_OCCLUDED;
+
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == expected_occlusion, "Got unexpected return code %#x.\n", status);
+
+    /* Note hwnd2 is not actually occluded but D3DKMTCheckOcclusion reports STATUS_GRAPHICS_PRESENT_OCCLUDED as well */
+    SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    ShowWindow(hwnd2, SW_SHOW);
+    occlusion_desc.hWnd = hwnd2;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == expected_occlusion, "Got unexpected return code %#x.\n", status);
+
+    /* Now hwnd is HWND_TOPMOST. Still reports STATUS_GRAPHICS_PRESENT_OCCLUDED */
+    ok(SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE), "Failed to SetWindowPos.\n");
+    ok(GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST, "No WS_EX_TOPMOST style.\n");
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == expected_occlusion, "Got unexpected return code %#x.\n", status);
+
+    DestroyWindow(hwnd2);
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == expected_occlusion, "Got unexpected return code %#x.\n", status);
+
+    check_owner_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    check_owner_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+    ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected return code %#x.\n", status);
+
+    /* Unset video present source owner */
+    set_owner_desc.hDevice = create_device_desc.hDevice;
+    set_owner_desc.pType = NULL;
+    set_owner_desc.pVidPnSourceId = NULL;
+    set_owner_desc.VidPnSourceCount = 0;
+    status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    occlusion_desc.hWnd = hwnd;
+    status = pD3DKMTCheckOcclusion(&occlusion_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    check_owner_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    check_owner_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected return code %#x.\n", status);
+
+    destroy_device_desc.hDevice = create_device_desc.hDevice;
+    status = pD3DKMTDestroyDevice(&destroy_device_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    status = pD3DKMTCloseAdapter(&close_adapter_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+    DestroyWindow(hwnd);
+}
+
 START_TEST(driver)
 {
     HMODULE gdi32 = GetModuleHandleA("gdi32.dll");
+    HMODULE dwmapi = LoadLibraryA("dwmapi.dll");
 
+    pD3DKMTCheckOcclusion = (void *)GetProcAddress(gdi32, "D3DKMTCheckOcclusion");
     pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32, "D3DKMTCheckVidPnExclusiveOwnership");
     pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32, "D3DKMTCloseAdapter");
     pD3DKMTCreateDevice = (void *)GetProcAddress(gdi32, "D3DKMTCreateDevice");
@@ -618,6 +807,9 @@ START_TEST(driver)
     pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
     pD3DKMTSetVidPnSourceOwner = (void *)GetProcAddress(gdi32, "D3DKMTSetVidPnSourceOwner");
 
+    if (dwmapi)
+        pDwmEnableComposition = (void *)GetProcAddress(dwmapi, "DwmEnableComposition");
+
     test_D3DKMTOpenAdapterFromGdiDisplayName();
     test_D3DKMTOpenAdapterFromHdc();
     test_D3DKMTCloseAdapter();
@@ -625,4 +817,7 @@ START_TEST(driver)
     test_D3DKMTDestroyDevice();
     test_D3DKMTCheckVidPnExclusiveOwnership();
     test_D3DKMTSetVidPnSourceOwner();
+    test_D3DKMTCheckOcclusion();
+
+    FreeLibrary(dwmapi);
 }
-- 
2.20.1




More information about the wine-devel mailing list