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

Zhiyi Zhang zzhang at codeweavers.com
Wed May 15 08:44:46 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>
---
 dlls/gdi32/tests/Makefile.in |   2 +-
 dlls/gdi32/tests/driver.c    | 382 +++++++++++++++++++++++++++++++++++
 2 files changed, 383 insertions(+), 1 deletion(-)

diff --git a/dlls/gdi32/tests/Makefile.in b/dlls/gdi32/tests/Makefile.in
index 9d82c278e9..6c32f22c1d 100644
--- a/dlls/gdi32/tests/Makefile.in
+++ b/dlls/gdi32/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = gdi32.dll
-IMPORTS   = user32 gdi32 advapi32
+IMPORTS   = user32 gdi32 advapi32 d3d10_1 dxgi
 
 C_SRCS = \
 	bitmap.c \
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index 81c41a1454..b4564c58ee 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -27,12 +27,18 @@
 #include "wingdi.h"
 #include "winuser.h"
 #include "winternl.h"
+#include "dwmapi.h"
+#define COBJMACROS
+#include "initguid.h"
+#include "dxgi1_6.h"
+#include <d3d11.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 +46,59 @@ 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 IDXGIAdapter *create_adapter(void)
+{
+    IDXGIFactory *factory;
+    IDXGIAdapter *adapter;
+    HRESULT hr;
+
+    if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory)))
+    {
+        trace("Failed to create IDXGIFactory, hr %#x.\n", hr);
+        return NULL;
+    }
+
+    adapter = NULL;
+    hr = IDXGIFactory_EnumAdapters(factory, 0, &adapter);
+    IDXGIFactory_Release(factory);
+    if (FAILED(hr))
+        trace("Failed to get adapter, hr %#x.\n", hr);
+    return adapter;
+}
+
+static IDXGIDevice *create_device(unsigned int flags)
+{
+    IDXGIDevice *dxgi_device;
+    ID3D10Device1 *device;
+    IDXGIAdapter *adapter;
+    HRESULT hr;
+
+    adapter = create_adapter();
+    hr = D3D10CreateDevice1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_FEATURE_LEVEL_10_0,
+                            D3D10_1_SDK_VERSION, &device);
+    if (adapter)
+        IDXGIAdapter_Release(adapter);
+    if (SUCCEEDED(hr))
+        goto success;
+
+    if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_WARP, NULL, flags, D3D10_FEATURE_LEVEL_10_0,
+                                     D3D10_1_SDK_VERSION, &device)))
+        goto success;
+    if (SUCCEEDED(D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_REFERENCE, NULL, flags, D3D10_FEATURE_LEVEL_10_0,
+                                     D3D10_1_SDK_VERSION, &device)))
+        goto success;
+
+    return NULL;
+
+success:
+    hr = ID3D10Device1_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
+    ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice\n");
+    ID3D10Device1_Release(device);
+
+    return dxgi_device;
+}
 
 static void test_D3DKMTOpenAdapterFromGdiDisplayName(void)
 {
@@ -603,10 +662,328 @@ static void test_D3DKMTSetVidPnSourceOwner(void)
     ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
 }
 
+static void test_D3DKMTCheckOcclusion(void)
+{
+    static const DWORD timeout = 2000;
+    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;
+    DXGI_SWAP_CHAIN_DESC swapchain_desc;
+    NTSTATUS expected_occlusion, status;
+    INT i, adapter_count = 0;
+    IDXGISwapChain *swapchain;
+    IDXGIFactory *factory;
+    IDXGIAdapter *adapter;
+    IDXGIDevice *device;
+    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");
+
+    DestroyWindow(hwnd2);
+
+    if (!(pD3DKMTCheckVidPnExclusiveOwnership && pD3DKMTCloseAdapter && pD3DKMTCreateDevice && pD3DKMTDestroyDevice
+          && pD3DKMTOpenAdapterFromGdiDisplayName && pD3DKMTSetVidPnSourceOwner))
+    {
+        skip("Required functions are unavailable.\n");
+        goto done;
+    }
+
+    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);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    /* Test swapchain fullscreen mode relationship with D3DKMTCheckOcclusion */
+    if (!(device = create_device(0)))
+    {
+        skip("Failed to create device.\n");
+        goto done;
+    }
+
+    hr = IDXGIDevice_GetAdapter(device, &adapter);
+    ok(SUCCEEDED(hr), "GetAdapter failed, hr %#x.\n", hr);
+
+    hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory, (void **)&factory);
+    ok(SUCCEEDED(hr), "GetParent failed, hr %#x.\n", hr);
+
+    memset(&swapchain_desc, 0, sizeof(swapchain_desc));
+    swapchain_desc.BufferDesc.Width = 800;
+    swapchain_desc.BufferDesc.Height = 600;
+    swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
+    swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
+    swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+    swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+    swapchain_desc.SampleDesc.Count = 1;
+    swapchain_desc.SampleDesc.Quality = 0;
+    swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    swapchain_desc.BufferCount = 1;
+    swapchain_desc.OutputWindow = hwnd;
+    swapchain_desc.Windowed = TRUE;
+    swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+    swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+    hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)device, &swapchain_desc, &swapchain);
+    ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
+
+    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 == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+    ok(SUCCEEDED(hr), "Failed to SetFullscreenState.\n");
+
+    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);
+
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+    ok(SUCCEEDED(hr), "Failed to SetFullscreenState.\n");
+    /* Leaving fullscreen could take several seconds to complete, wait a while to get accurate results for
+     * D3DKMTCheckOcclusion and D3DKMTCheckVidPnExclusiveOwnership. */
+    Sleep(timeout);
+
+    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, "Got unexpected return code %#x.\n", status);
+
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+    ok(SUCCEEDED(hr), "Failed to SetFullscreenState.\n");
+
+    /* Invisible window, even HWND_TOP, doesn't break swapchain out of fullscreen, and doesn't change video present
+     * network ownership */
+    hwnd2 = CreateWindowA("static", "static2", WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, 0);
+    ok(hwnd2 != NULL, "Failed to create window.\n");
+    SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+    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);
+
+    /* Visible window, even with HWND_BOTTOM, breaks swapchain out of fullscreen */
+    SetWindowPos(hwnd2, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    ShowWindow(hwnd2, SW_SHOW);
+    Sleep(timeout);
+    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, "Got unexpected return code %#x.\n", status);
+
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+    ok(SUCCEEDED(hr), "Failed to SetFullscreenState.\n");
+    Sleep(timeout);
+
+    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, "Got unexpected return code %#x.\n", status);
+
+    IDXGISwapChain_Release(swapchain);
+    IDXGIAdapter_Release(adapter);
+    IDXGIDevice_Release(device);
+    IDXGIFactory_Release(factory);
+
+    /* 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);
+
+    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);
+    /* 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);
+
+    destroy_device_desc.hDevice = create_device_desc.hDevice;
+    status = pD3DKMTDestroyDevice(&destroy_device_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+done:
+    if (pD3DKMTCloseAdapter)
+    {
+        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 = LoadLibraryA("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");
@@ -615,6 +992,10 @@ START_TEST(driver)
     pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
     pD3DKMTSetVidPnSourceOwner = (void *)GetProcAddress(gdi32, "D3DKMTSetVidPnSourceOwner");
 
+    if (dwmapi)
+        pDwmEnableComposition = (void *)GetProcAddress(dwmapi, "DwmEnableComposition");
+
+    test_D3DKMTCheckOcclusion();
     test_D3DKMTCheckVidPnExclusiveOwnership();
     test_D3DKMTCloseAdapter();
     test_D3DKMTCreateDevice();
@@ -624,4 +1005,5 @@ START_TEST(driver)
     test_D3DKMTSetVidPnSourceOwner();
 
     FreeLibrary(gdi32);
+    FreeLibrary(dwmapi);
 }
-- 
2.20.1




More information about the wine-devel mailing list