[PATCH 4/5] dxgi/tests: Add factory window association tests.

Zhiyi Zhang zzhang at codeweavers.com
Tue Apr 23 07:59:09 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/dxgi/tests/Makefile.in |   2 +-
 dlls/dxgi/tests/dxgi.c      | 233 +++++++++++++++++++++++++++++++++++-
 2 files changed, 233 insertions(+), 2 deletions(-)

diff --git a/dlls/dxgi/tests/Makefile.in b/dlls/dxgi/tests/Makefile.in
index 1c99d70957..fbce9d3dd0 100644
--- a/dlls/dxgi/tests/Makefile.in
+++ b/dlls/dxgi/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = dxgi.dll
-IMPORTS   = d3d10_1 dxgi user32
+IMPORTS   = d3d10_1 d3d11 dxgi user32
 
 C_SRCS = \
 	dxgi.c
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 79e4bc0c15..fe3a2596e0 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -40,9 +40,16 @@ static PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
 static PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
 
 static unsigned int use_adapter_idx;
+static BOOL enable_debug_layer;
 static BOOL use_warp_adapter;
 static BOOL use_mt = TRUE;
 
+struct device_desc
+{
+    const D3D_FEATURE_LEVEL *feature_level;
+    UINT flags;
+};
+
 static struct test_entry
 {
     void (*test)(void);
@@ -539,6 +546,56 @@ success:
     return dxgi_device;
 }
 
+static ID3D11Device *create_d3d11_device(const struct device_desc *desc)
+{
+    static const D3D_FEATURE_LEVEL default_feature_level[] =
+    {
+        D3D_FEATURE_LEVEL_11_0,
+        D3D_FEATURE_LEVEL_10_1,
+        D3D_FEATURE_LEVEL_10_0,
+    };
+    const D3D_FEATURE_LEVEL *feature_level;
+    UINT flags = desc ? desc->flags : 0;
+    unsigned int feature_level_count;
+    IDXGIAdapter *adapter;
+    ID3D11Device *device;
+    HRESULT hr;
+
+    if (desc && desc->feature_level)
+    {
+        feature_level = desc->feature_level;
+        feature_level_count = 1;
+    }
+    else
+    {
+        feature_level = default_feature_level;
+        feature_level_count = ARRAY_SIZE(default_feature_level);
+    }
+
+    if (enable_debug_layer)
+        flags |= D3D11_CREATE_DEVICE_DEBUG;
+
+    if ((adapter = create_adapter()))
+    {
+        hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, feature_level, feature_level_count,
+                D3D11_SDK_VERSION, &device, NULL, NULL);
+        IDXGIAdapter_Release(adapter);
+        return SUCCEEDED(hr) ? device : NULL;
+    }
+
+    if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, feature_level, feature_level_count,
+            D3D11_SDK_VERSION, &device, NULL, NULL)))
+        return device;
+    if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, flags, feature_level, feature_level_count,
+            D3D11_SDK_VERSION, &device, NULL, NULL)))
+        return device;
+    if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, flags, feature_level, feature_level_count,
+            D3D11_SDK_VERSION, &device, NULL, NULL)))
+        return device;
+
+    return NULL;
+}
+
 static ID3D12Device *create_d3d12_device(void)
 {
     IDXGIAdapter *adapter;
@@ -4985,6 +5042,180 @@ done:
     ok(!refcount, "Factory has %u references left.\n", refcount);
 }
 
+static void test_window_association(void)
+{
+    DXGI_SWAP_CHAIN_DESC swapchain_desc;
+    IDXGIFactory *factory, *factory2;
+    IDXGIDevice *devices[2] = {0};
+    ID3D11Device *d3d11_device;
+    IDXGISwapChain *swapchain;
+    IDXGIAdapter *adapter;
+    HWND hwnd, hwnd2;
+    BOOL fullscreen;
+    ULONG refcount;
+    HRESULT hr;
+    INT i, j;
+
+    static const struct
+    {
+        UINT flag;
+        BOOL expect_fullscreen;
+        BOOL broken_d3d10;
+    }
+    tests[] =
+    {
+        /* There are two reasons why VK_TAB and VK_ESC are not tested here.
+         * 1. Posting them to the window doesn't exit fullscreen like Alt+Enter does.
+         *    Alt+Tab and Alt+Esc are handled somewhere else, e.g., not calling IDXGISwapChain::Present
+         *    will break Alt+Tab and Alt+Esc while Alt+Enter will still function.
+         * 2. Posting them hangs the posting thread. Another thread keep sending input is needed to avoid the hang.
+         *    The hang is not because of flush_events. */
+        {0, TRUE},
+        {0, FALSE},
+        {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
+        {DXGI_MWA_NO_WINDOW_CHANGES, FALSE},
+        {DXGI_MWA_NO_ALT_ENTER, FALSE, TRUE},
+        {DXGI_MWA_NO_ALT_ENTER, FALSE},
+        {DXGI_MWA_NO_PRINT_SCREEN, TRUE},
+        {DXGI_MWA_NO_PRINT_SCREEN, FALSE},
+        {0, TRUE},
+        {0, FALSE}
+    };
+
+    /* d3d10 */
+    devices[0] = create_device(0);
+
+    /* d3d11 */
+    d3d11_device = create_d3d11_device(NULL);
+    if (d3d11_device)
+    {
+        hr = ID3D11Device_QueryInterface(d3d11_device, &IID_IDXGIDevice, (void **)&devices[1]);
+        ok(SUCCEEDED(hr), "Created device does not implement IDXGIDevice\n");
+        ID3D11Device_Release(d3d11_device);
+    }
+
+    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 = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+    swapchain_desc.Windowed = TRUE;
+    swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+    swapchain_desc.Flags = 0;
+
+    hwnd2 = CreateWindowA("static", "dxgi_test2", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+    hr = CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory2);
+    ok(hr == S_OK, "Failed to create DXGI factory, hr %#x.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(devices); i++)
+    {
+        if (!devices[i])
+        {
+            skip("Create device failed. Skipping IDXGIFactory window association test.\n");
+            continue;
+        }
+
+        hr = IDXGIDevice_GetAdapter(devices[i], &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);
+
+        /* Parameter check */
+        hr = IDXGIFactory_GetWindowAssociation(factory, NULL);
+        ok(hr == DXGI_ERROR_INVALID_CALL, "GetWindowAssociation failed, hr %#x.\n", hr);
+
+        for (j = 0; j <= DXGI_MWA_VALID; j++)
+        {
+            hr = IDXGIFactory_MakeWindowAssociation(factory, NULL, j);
+            ok(SUCCEEDED(hr), "MakeWindowAssociation failed, flags %#x, hr %#x.\n", j, hr);
+
+            hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, j);
+            ok(SUCCEEDED(hr), "MakeWindowAssociation failed, flags %#x, hr %#x.\n", j, hr);
+
+            hwnd = (HWND)0xdeadbeef;
+            hr = IDXGIFactory_GetWindowAssociation(factory, &hwnd);
+            ok(SUCCEEDED(hr), "GetWindowAssociation failed, flags %#x, hr %#x.\n", j, hr);
+            /* Yes, GetWindowAssociation always return NULL for hwnd even though MakeWindowAssociation and
+             * GetWindowAssociation are successfully called. I wonder why. */
+            ok(!hwnd, "Expect null associated window.\n");
+        }
+
+        hr = IDXGIFactory_MakeWindowAssociation(factory, swapchain_desc.OutputWindow, DXGI_MWA_VALID + 1);
+        ok(hr == DXGI_ERROR_INVALID_CALL, "MakeWindowAssociation succeeded, hr %#x.\n", hr);
+
+        /* Alt+Enter tests */
+        hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown *)devices[i], &swapchain_desc, &swapchain);
+        ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
+
+        hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+        ok(SUCCEEDED(hr) || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
+               || broken(hr == DXGI_ERROR_UNSUPPORTED), /* Win 7 testbot */
+           "SetFullscreenState failed, hr %#x.\n", hr);
+        if (FAILED(hr))
+            skip("Could not change fullscreen state.\n");
+        else
+        {
+            hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+            ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+            for (j = 0; j < ARRAY_SIZE(tests); j++)
+            {
+                /* Associate a window first with opposite flags */
+                hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, (~tests[j].flag) & DXGI_MWA_VALID);
+                ok(SUCCEEDED(hr), "Test %d: MakeWindowAssociation failed, hr %#x.\n", j, hr);
+
+                /* Associate current test window */
+                hwnd = tests[j].flag ? swapchain_desc.OutputWindow : NULL;
+                hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd, tests[j].flag);
+                ok(SUCCEEDED(hr), "Test %d: MakeWindowAssociation failed, hr %#x.\n", j, hr);
+
+                /* Associate a new test window doesn't override old window */
+                hr = IDXGIFactory_MakeWindowAssociation(factory, hwnd2, (~tests[j].flag) & DXGI_MWA_VALID);
+                ok(SUCCEEDED(hr), "Test %d: MakeWindowAssociation failed, hr %#x.\n", j, hr);
+
+                /* Wrong factory doesn't affect current test window */
+                hr = IDXGIFactory_MakeWindowAssociation(factory2, hwnd, (~tests[j].flag) & DXGI_MWA_VALID);
+                ok(SUCCEEDED(hr), "Test %d: MakeWindowAssociation failed, hr %#x.\n", j, hr);
+
+                /* Post synthesized Alt + VK_RETURN WM_SYSKEYDOWN */
+                PostMessageA(swapchain_desc.OutputWindow, WM_SYSKEYDOWN, VK_RETURN,
+                             (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x20000001);
+                flush_events();
+                hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+                ok(SUCCEEDED(hr), "Test %d: GetFullscreenState failed, hr %#x.\n", j, hr);
+                ok(fullscreen == tests[j].expect_fullscreen || broken(tests[j].broken_d3d10 && i == 0 && fullscreen),
+                   "Test %d: got unexpected fullscreen %#x.\n", j, fullscreen);
+            }
+        }
+
+        /* Set to windowed mode before releasing resources, otherwise there might be unhandled exceptions */
+        hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+        ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
+
+        refcount = IDXGISwapChain_Release(swapchain);
+        ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+        refcount = IDXGIDevice_Release(devices[i]);
+        ok(!refcount, "Device has %u references left.\n", refcount);
+        refcount = IDXGIAdapter_Release(adapter);
+        ok(!refcount, "IDXGIAdapter has %u references left.\n", refcount);
+        refcount = IDXGIFactory_Release(factory);
+        ok(!refcount, "Factory has %u references left.\n", refcount);
+    }
+
+    refcount = IDXGIFactory_Release(factory2);
+    ok(!refcount, "Factory has %u references left.\n", refcount);
+    DestroyWindow(hwnd2);
+    DestroyWindow(swapchain_desc.OutputWindow);
+}
+
 static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
 {
     IDXGIDevice *device;
@@ -5029,7 +5260,6 @@ static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
 START_TEST(dxgi)
 {
     HMODULE dxgi_module, d3d12_module;
-    BOOL enable_debug_layer = FALSE;
     unsigned int argc, i;
     ID3D12Debug *debug;
     char **argv;
@@ -5084,6 +5314,7 @@ START_TEST(dxgi)
     test_swapchain_parameters();
     test_swapchain_window_messages();
     test_swapchain_window_styles();
+    test_window_association();
     run_on_d3d10(test_swapchain_resize);
     run_on_d3d10(test_swapchain_present);
     run_on_d3d10(test_swapchain_backbuffer_index);
-- 
2.20.1





More information about the wine-devel mailing list