[PATCH 01/10] dxgi/tests: Add IDXGIOutput ownership tests.

Zhiyi Zhang zzhang at codeweavers.com
Wed May 15 08:43:03 CDT 2019


Mostly to show that TakeOwnership and ReleaseOwnership
are based on VidPN ownership.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/dxgi/tests/dxgi.c | 178 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 177 insertions(+), 1 deletion(-)

diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 79e4bc0c15..5e1fb43b7e 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -17,11 +17,15 @@
  */
 
 #include <assert.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #define COBJMACROS
 #include "initguid.h"
 #include "dxgi1_6.h"
 #include "d3d11.h"
 #include "d3d12.h"
+#include "winternl.h"
+#include "ddk/d3dkmthk.h"
 #include "wine/heap.h"
 #include "wine/test.h"
 
@@ -36,6 +40,10 @@ static DEVMODEW registry_mode;
 static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
 static HRESULT (WINAPI *pCreateDXGIFactory2)(UINT flags, REFIID iid, void **factory);
 
+static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *);
+static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
+static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
+
 static PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
 static PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
 
@@ -4985,6 +4993,167 @@ done:
     ok(!refcount, "Factory has %u references left.\n", refcount);
 }
 
+static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
+{
+    static const DWORD timeout = 1000;
+    static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
+    D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+    D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
+    D3DKMT_CLOSEADAPTER close_adapter_desc;
+    DXGI_SWAP_CHAIN_DESC swapchain_desc;
+    IDXGISwapChain *swapchain;
+    IDXGIFactory *factory;
+    IDXGIOutput *output;
+    BOOL fullscreen;
+    ULONG refcount;
+    NTSTATUS status;
+    HRESULT hr;
+
+    if (!pD3DKMTCheckVidPnExclusiveOwnership || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND
+        || !pD3DKMTCloseAdapter || !pD3DKMTOpenAdapterFromGdiDisplayName)
+    {
+        skip("Required functions are unavailable.\n");
+        return;
+    }
+
+    lstrcpyW(open_adapter_gdi_desc.DeviceName, display1W);
+    status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+
+    check_ownership_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    check_ownership_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n", status);
+
+    get_factory(device, is_d3d12, &factory);
+
+    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 = is_d3d12 ? 2 : 1;
+    swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+    swapchain_desc.Windowed = TRUE;
+    swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
+    swapchain_desc.Flags = 0;
+
+    hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+    ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
+
+    /* Swapchain in fullscreen mode */
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+    /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines. DXGI_ERROR_UNSUPPORTED on Win 7 testbot. */
+    if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
+    {
+        skip("Failed to change fullscreen state.\n");
+        goto done;
+    }
+    todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    Sleep(timeout);
+    output = NULL;
+    fullscreen = FALSE;
+    hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
+    todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen state.\n");
+    todo_wine_if(is_d3d12) ok(output != NULL, "Expect output not null.\n");
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    if (is_d3d12)
+        ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n",
+           status);
+    else
+        todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected status %#x.\n", status);
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : E_INVALIDARG), "Got unexpected hr %#x.\n", hr);
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+    /* Calling IDXGIOutput_ReleaseOwnership makes it unoccluded. So we can be confident about IDXGIOutput_TakeOwnership
+     * was called in IDXGISwapChain_SetFullscreenState */
+    if (output) IDXGIOutput_ReleaseOwnership(output);
+    Sleep(timeout);
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n",
+       status);
+
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), "Got unexpected hr %#x.\n", hr);
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n",
+       status);
+    if (output) IDXGIOutput_ReleaseOwnership(output);
+
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    /* So the following results shows that IDXGIOutput_TakeOwnership(output, device, TRUE) is used in
+     * SetFullscreenState(swapchain, TRUE, NULL)
+     *
+     * This make me believe the MSDN documentation is saying the opposite about the last parameter,
+     * "HRESULT TakeOwnership(IUnknown *pDevice, BOOL Exclusive);
+     *  Name: Exclusive Type: BOOL
+     *  Set to TRUE to enable other threads or applications to take ownership of the device; otherwise, set to FALSE."
+     *
+     * Reasons:
+     * 1. The parameter name is called 'Exclusive'
+     * 2. D3DKMTSetVidPnSourceOwner(D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE) makes D3DKMTCheckVidPnExclusiveOwnership return
+     *    STATUS_GRAPHICS_PRESENT_OCCLUDED. And D3DKMTSetVidPnSourceOwner(D3DKMT_VIDPNSOURCEOWNER_SHARED) makes
+     *    D3DKMTCheckVidPnExclusiveOwnership return STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE. So the opposite mapping of
+     *    what MSDN is saying is consistent with the tests.
+     */
+    if (is_d3d12)
+        ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n",
+           status);
+    else
+        todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected status %#x.\n", status);
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : E_INVALIDARG), "Got unexpected hr %#x.\n", hr);
+    if (output) IDXGIOutput_ReleaseOwnership(output);
+
+    /* Swapchain in windowed mode */
+    hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+    todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    Sleep(timeout);
+    fullscreen = TRUE;
+    hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+    todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    todo_wine_if(is_d3d12) ok(!fullscreen, "Unexpected fullscreen state.\n");
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), "Got unexpected hr %#x.\n", hr);
+
+    if (output) hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+    todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    if (is_d3d12)
+        ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n",
+           status);
+    else
+        todo_wine ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected status %#x.\n", status);
+    if (output) IDXGIOutput_ReleaseOwnership(output);
+    status = pD3DKMTCheckVidPnExclusiveOwnership(&check_ownership_desc);
+    ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected status %#x.\n", status);
+
+    if (output) IDXGIOutput_Release(output);
+
+done:
+    wait_device_idle(device);
+
+    IDXGISwapChain_Release(swapchain);
+    DestroyWindow(swapchain_desc.OutputWindow);
+    refcount = IDXGIFactory_Release(factory);
+    ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
+
+    close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+    status = pD3DKMTCloseAdapter(&close_adapter_desc);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+}
+
 static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
 {
     IDXGIDevice *device;
@@ -5028,7 +5197,7 @@ static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
 
 START_TEST(dxgi)
 {
-    HMODULE dxgi_module, d3d12_module;
+    HMODULE dxgi_module, d3d12_module, gdi32_module;
     BOOL enable_debug_layer = FALSE;
     unsigned int argc, i;
     ID3D12Debug *debug;
@@ -5038,6 +5207,11 @@ START_TEST(dxgi)
     pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
     pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
 
+    gdi32_module = GetModuleHandleA("gdi32.dll");
+    pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32_module, "D3DKMTCheckVidPnExclusiveOwnership");
+    pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32_module, "D3DKMTCloseAdapter");
+    pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32_module, "D3DKMTOpenAdapterFromGdiDisplayName");
+
     registry_mode.dmSize = sizeof(registry_mode);
     ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &registry_mode), "Failed to get display mode.\n");
 
@@ -5088,6 +5262,7 @@ START_TEST(dxgi)
     run_on_d3d10(test_swapchain_present);
     run_on_d3d10(test_swapchain_backbuffer_index);
     run_on_d3d10(test_swapchain_formats);
+    run_on_d3d10(test_output_ownership);
 
     if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
     {
@@ -5108,6 +5283,7 @@ START_TEST(dxgi)
     run_on_d3d12(test_swapchain_present);
     run_on_d3d12(test_swapchain_backbuffer_index);
     run_on_d3d12(test_swapchain_formats);
+    run_on_d3d12(test_output_ownership);
 
     FreeLibrary(d3d12_module);
 }
-- 
2.20.1





More information about the wine-devel mailing list