[PATCH v2 resend 1/3] dxgi/tests: Add IDXGIOutput ownership tests.
Zhiyi Zhang
zzhang at codeweavers.com
Mon Jun 10 08:04:44 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 | 226 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 225 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 79e4bc0c15..765b174af6 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;
@@ -43,6 +51,9 @@ static unsigned int use_adapter_idx;
static BOOL use_warp_adapter;
static BOOL use_mt = TRUE;
+static const DWORD wait_timeout = 1000;
+static const DWORD wait_step = 100;
+
static struct test_entry
{
void (*test)(void);
@@ -113,6 +124,24 @@ static ULONG get_refcount(void *iface)
return IUnknown_Release(unknown);
}
+/* This is to get a result from a function that returns different result if called too early */
+#define wait_result(a, b, c, d) wait_result_(__LINE__, a, b, c, d)
+#define wait_result_(line, func, arg, expected, todo) \
+ do \
+ { \
+ DWORD total_time = 0; \
+ typeof(expected) got; \
+ do \
+ { \
+ got = func(arg); \
+ if (got == expected) \
+ break; \
+ Sleep(wait_step); \
+ total_time += wait_step; \
+ } while (total_time < wait_timeout); \
+ todo_wine_if(todo) ok_(__FILE__, line)(got == expected, "Expect %#x, got %#x.\n", expected, got); \
+ } while (0)
+
#define check_interface(a, b, c, d) check_interface_(__LINE__, a, b, c, d)
static HRESULT check_interface_(unsigned int line, void *iface, REFIID iid,
BOOL supported, BOOL is_broken)
@@ -4985,6 +5014,194 @@ done:
ok(!refcount, "Factory has %u references left.\n", refcount);
}
+static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
+{
+ D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+ D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ DXGI_SWAP_CHAIN_DESC swapchain_desc;
+ DXGI_OUTPUT_DESC output_desc;
+ ID3D12Device *d3d12_device;
+ IDXGISwapChain *swapchain;
+ IDXGIFactory4 *factory4;
+ IDXGIFactory *factory;
+ IDXGIAdapter *adapter;
+ IDXGIOutput *output;
+ BOOL fullscreen;
+ NTSTATUS status;
+ ULONG refcount;
+ LUID luid;
+ HRESULT hr;
+
+ if (!pD3DKMTCheckVidPnExclusiveOwnership || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND)
+ {
+ skip("D3DKMTCheckVidPnExclusiveOwnership() is unavailable.\n");
+ return;
+ }
+
+ get_factory(device, is_d3d12, &factory);
+
+ if (is_d3d12)
+ {
+ hr = ID3D12CommandQueue_GetDevice((ID3D12CommandQueue *)device, &IID_ID3D12Device, (void **)&d3d12_device);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ luid = ID3D12Device_GetAdapterLuid(d3d12_device);
+ ID3D12Device_Release(d3d12_device);
+ hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
+ if (hr == E_NOINTERFACE)
+ {
+ skip("DXGI 1.4 unsupported.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
+ IDXGIFactory4_Release(factory4);
+ if (hr == DXGI_ERROR_NOT_FOUND)
+ {
+ skip("Wine doesn't support IDXGIFactory4_EnumAdapterByLuid.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ else
+ {
+ hr = IDXGIDevice_GetAdapter((IDXGIDevice *)device, &adapter);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+
+ hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
+ IDXGIAdapter_Release(adapter);
+ if (hr == DXGI_ERROR_NOT_FOUND)
+ {
+ skip("Adapter doesn't have any outputs.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGIOutput_GetDesc(output, &output_desc);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ lstrcpyW(open_adapter_gdi_desc.DeviceName, output_desc.DeviceName);
+ 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;
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ 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, output);
+ /* 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);
+ fullscreen = FALSE;
+ 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");
+ if (is_d3d12)
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+ else
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : E_INVALIDARG), "Got unexpected hr %#x.\n", hr);
+ 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 */
+ IDXGIOutput_ReleaseOwnership(output);
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ /* IDXGIOutput_TakeOwnership always return E_NOINTERFACE for d3d12. Tests finished */
+ if (is_d3d12)
+ goto done;
+
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
+ IDXGIOutput_ReleaseOwnership(output);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ /* 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.
+ */
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+ IDXGIOutput_ReleaseOwnership(output);
+
+ /* Swapchain in windowed mode */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!fullscreen, "Unexpected fullscreen state.\n");
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ IDXGIOutput_ReleaseOwnership(output);
+ wait_result(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+done:
+ IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ wait_device_idle(device);
+
+ IDXGIOutput_Release(output);
+ 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 +5245,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 +5255,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, ®istry_mode), "Failed to get display mode.\n");
@@ -5088,6 +5310,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 +5331,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