[PATCH 3/3] dxgi/tests: Test presentation parameter combinations (v2).

Stefan Dösinger stefan at codeweavers.com
Thu Aug 27 16:05:03 CDT 2015


Version 2: Make Vista (no DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL support) and
the testbot (creating fullscreen swapchains without focus) happy.
---
 dlls/dxgi/factory.c      |  30 +++++++-
 dlls/dxgi/tests/device.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++
 include/dxgi.idl         |   2 +
 3 files changed, 215 insertions(+), 4 deletions(-)

diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c
index a716e1b..ebae9c6 100644
--- a/dlls/dxgi/factory.c
+++ b/dlls/dxgi/factory.c
@@ -190,21 +190,43 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChain(IDXGIFactory1 *ifa
     struct wined3d_swapchain_desc wined3d_desc;
     IWineDXGIDevice *dxgi_device;
     HRESULT hr;
+    UINT min_buffer_count;
 
     FIXME("iface %p, device %p, desc %p, swapchain %p partial stub!\n", iface, device, desc, swapchain);
 
-    hr = IUnknown_QueryInterface(device, &IID_IWineDXGIDevice, (void **)&dxgi_device);
-    if (FAILED(hr))
+    switch (desc->SwapEffect)
     {
-        ERR("This is not the device we're looking for\n");
-        return hr;
+        case DXGI_SWAP_EFFECT_DISCARD:
+        case DXGI_SWAP_EFFECT_SEQUENTIAL:
+            min_buffer_count = 1;
+            break;
+
+        case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
+            min_buffer_count = 2;
+            break;
+
+        default:
+            WARN("Invalid swap effect %u used, returning DXGI_ERROR_INVALID_CALL.\n", desc->SwapEffect);
+            return DXGI_ERROR_INVALID_CALL;
     }
 
+    if (desc->BufferCount < min_buffer_count || desc->BufferCount > 16)
+    {
+        WARN("BufferCount is %u, returning DXGI_ERROR_INVALID_CALL.\n", desc->BufferCount);
+        return DXGI_ERROR_INVALID_CALL;
+    }
     if (!desc->OutputWindow)
     {
         FIXME("No output window, should use factory output window\n");
     }
 
+    hr = IUnknown_QueryInterface(device, &IID_IWineDXGIDevice, (void **)&dxgi_device);
+    if (FAILED(hr))
+    {
+        ERR("This is not the device we're looking for\n");
+        return hr;
+    }
+
     FIXME("Ignoring SwapEffect and Flags\n");
 
     wined3d_desc.backbuffer_width = desc->BufferDesc.Width;
diff --git a/dlls/dxgi/tests/device.c b/dlls/dxgi/tests/device.c
index c0eda12..8995680 100644
--- a/dlls/dxgi/tests/device.c
+++ b/dlls/dxgi/tests/device.c
@@ -21,6 +21,8 @@
 #include "d3d11.h"
 #include "wine/test.h"
 
+static DEVMODEW registry_mode;
+
 static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
 
 static ULONG get_refcount(IUnknown *iface)
@@ -1018,10 +1020,194 @@ static void test_swapchain_resize(void)
     DestroyWindow(window);
 }
 
+static void test_swapchain_parameters(void)
+{
+    IDXGISwapChain *swapchain;
+    IUnknown *obj;
+    IDXGIAdapter *adapter;
+    IDXGIFactory *factory;
+    IDXGIDevice *device;
+    IDXGIResource *resource;
+    DXGI_SWAP_CHAIN_DESC desc;
+    HRESULT hr;
+    unsigned int i, j;
+    ULONG refcount;
+    DXGI_USAGE usage, expected_usage;
+    HWND window;
+    static const struct
+    {
+        BOOL windowed;
+        UINT buffer_count;
+        DXGI_SWAP_EFFECT swap_effect;
+        HRESULT hr, vista_hr;
+        UINT highest_accessible_buffer;
+    }
+    tests[] =
+    {
+        {TRUE,   0, DXGI_SWAP_EFFECT_DISCARD,         DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   1, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0},
+        {TRUE,   2, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0},
+        {TRUE,   0, DXGI_SWAP_EFFECT_SEQUENTIAL,      DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   1, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     0},
+        {TRUE,   2, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     1},
+        {TRUE,   3, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     2},
+        {TRUE,   0, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   1, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   2, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0}, //10
+        {TRUE,   1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL,  1},
+        {TRUE,   3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL,  2},
+        {TRUE,   0, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   1, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,   2, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,  16, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0},
+        {TRUE,  16, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                    15},
+        {TRUE,  16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL, 15},
+        {TRUE,  17, DXGI_SWAP_EFFECT_DISCARD,         DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0}, //20
+        {TRUE,  17, DXGI_SWAP_EFFECT_SEQUENTIAL,      DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {TRUE,  17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+
+        {FALSE,  0, DXGI_SWAP_EFFECT_DISCARD,         DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  1, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0}, //24
+        {FALSE,  2, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0},
+        {FALSE,  0, DXGI_SWAP_EFFECT_SEQUENTIAL,      DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  1, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     0},
+        {FALSE,  2, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     1},
+        {FALSE,  3, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                     2},
+        {FALSE,  0, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0}, //30
+        {FALSE,  1, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  2, 2 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  0, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  1, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  2, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL,  1},
+        {FALSE,  3, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL,  2},
+        {FALSE,  0, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  1, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE,  2, 4 /* undefined */,                DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE, 16, DXGI_SWAP_EFFECT_DISCARD,         S_OK,                    S_OK,                     0}, //40
+        {FALSE, 16, DXGI_SWAP_EFFECT_SEQUENTIAL,      S_OK,                    S_OK,                    15},
+        {FALSE, 16, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, S_OK,                    DXGI_ERROR_INVALID_CALL, 15},
+        {FALSE, 17, DXGI_SWAP_EFFECT_DISCARD,         DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE, 17, DXGI_SWAP_EFFECT_SEQUENTIAL,      DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+        {FALSE, 17, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_INVALID_CALL,  0},
+    };
+
+    if (!(device = create_device()))
+    {
+        skip("Failed to create device, skipping tests.\n");
+        return;
+    }
+    window = CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 640, 480, 0, 0, 0, 0);
+
+    hr = IDXGIDevice_QueryInterface(device, &IID_IUnknown, (void **)&obj);
+    ok(SUCCEEDED(hr), "IDXGIDevice does not implement IUnknown\n");
+
+    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);
+
+    for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
+    {
+        memset(&desc, 0, sizeof(desc));
+        desc.BufferDesc.Width = registry_mode.dmPelsWidth;
+        desc.BufferDesc.Height = registry_mode.dmPelsHeight;
+        desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+        desc.SampleDesc.Count = 1;
+        desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+        desc.OutputWindow = window;
+
+        desc.Windowed = tests[i].windowed;
+        desc.BufferCount = tests[i].buffer_count;
+        desc.SwapEffect = tests[i].swap_effect;
+
+        hr = IDXGIFactory_CreateSwapChain(factory, obj, &desc, &swapchain);
+        ok(hr == tests[i].hr || broken(hr == tests[i].vista_hr)
+                || (SUCCEEDED(tests[i].hr) && hr == DXGI_STATUS_OCCLUDED),
+                "Got unexpected hr %#x, test %u.\n", hr, i);
+        if (FAILED(hr))
+            continue;
+
+        hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGIResource, (void **)&resource);
+        todo_wine ok(SUCCEEDED(hr), "GetBuffer(0) failed, hr %#x, test %u.\n", hr, i);
+        if (FAILED(hr))
+        {
+            hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+            todo_wine ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
+
+            IDXGISwapChain_Release(swapchain);
+            continue;
+        }
+
+        expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+        if (tests[i].swap_effect == DXGI_SWAP_EFFECT_DISCARD)
+            expected_usage |= DXGI_USAGE_DISCARD_ON_PRESENT;
+        hr = IDXGIResource_GetUsage(resource, &usage);
+        ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u.\n", hr, i);
+        ok(usage == expected_usage, "Got usage %x, expected %x, test %u.\n", usage, expected_usage, i);
+
+        IDXGIResource_Release(resource);
+
+        hr = IDXGISwapChain_GetDesc(swapchain, &desc);
+        ok(SUCCEEDED(hr), "Failed to get swapchain desc, hr %#x.\n", hr);
+
+        for (j = 1; j <= tests[i].highest_accessible_buffer; j++)
+        {
+            hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
+            ok(SUCCEEDED(hr), "GetBuffer(%u) failed, hr %#x, test %u.\n", hr, i, j);
+
+            expected_usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+
+            /* Buffers > 0 are supposed to be read only. This is the case except that in
+             * fullscreen mode the last backbuffer (BufferCount - 1) is writeable. This
+             * is not the case if an unsupported refresh rate is passed for some reason,
+             * probably because the invalid refresh rate triggers a kinda-sorta windowed
+             * mode.
+             *
+             * This last buffer acts as a shadow frontbuffer. Writing to it doesn't show
+             * the draw on the screen right away (Aero on or off doesn't matter), but
+             * Present with DXGI_PRESENT_DO_NOT_SEQUENCE will show the modifications.
+             *
+             * Note that if the application doesn't have focused creating a fullscreen
+             * swapchain returns DXGI_STATUS_OCCLUDED and we get a windowed swapchain,
+             * so use the Windowed property of the swapchain that was actually created. */
+            if (desc.Windowed || j < tests[i].highest_accessible_buffer)
+                expected_usage |= DXGI_USAGE_READ_ONLY;
+
+            hr = IDXGIResource_GetUsage(resource, &usage);
+            ok(SUCCEEDED(hr), "Failed to get resource usage, hr %#x, test %u, buffer %u.\n", hr, i, j);
+            ok(usage == expected_usage, "Got usage %x, expected %x, test %u, buffer %u.\n",
+                    usage, expected_usage, i, j);
+
+            IDXGIResource_Release(resource);
+        }
+        hr = IDXGISwapChain_GetBuffer(swapchain, j, &IID_IDXGIResource, (void **)&resource);
+        ok(hr == DXGI_ERROR_INVALID_CALL, "GetBuffer(%u) returned unexpected hr %#x, test %u.\n", j, hr, i);
+
+        hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+        todo_wine ok(SUCCEEDED(hr), "SetFullscreenState failed, hr %#x.\n", hr);
+
+        IDXGISwapChain_Release(swapchain);
+    }
+
+    IDXGIFactory_Release(factory);
+    IDXGIAdapter_Release(adapter);
+    IUnknown_Release(obj);
+    refcount = IDXGIDevice_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(device)
 {
     pCreateDXGIFactory1 = (void *)GetProcAddress(GetModuleHandleA("dxgi.dll"), "CreateDXGIFactory1");
 
+    registry_mode.dmSize = sizeof(registry_mode);
+    ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
+
     test_adapter_desc();
     test_device_interfaces();
     test_create_surface();
@@ -1031,4 +1217,5 @@ START_TEST(device)
     test_create_factory();
     test_private_data();
     test_swapchain_resize();
+    test_swapchain_parameters();
 }
diff --git a/include/dxgi.idl b/include/dxgi.idl
index 009a6b5..dd16309 100644
--- a/include/dxgi.idl
+++ b/include/dxgi.idl
@@ -60,6 +60,8 @@ const DXGI_USAGE DXGI_USAGE_RENDER_TARGET_OUTPUT    = 0x20L;
 const DXGI_USAGE DXGI_USAGE_BACK_BUFFER             = 0x40L;
 const DXGI_USAGE DXGI_USAGE_SHARED                  = 0x80L;
 const DXGI_USAGE DXGI_USAGE_READ_ONLY               = 0x100L;
+const DXGI_USAGE DXGI_USAGE_DISCARD_ON_PRESENT      = 0x200L;
+const DXGI_USAGE DXGI_USAGE_UNORDERED_ACCESS        = 0x400L;
 
 const UINT DXGI_ENUM_MODES_INTERLACED               = 1;
 const UINT DXGI_ENUM_MODES_SCALING                  = 2;
-- 
2.4.6




More information about the wine-patches mailing list