Needed by Orbiter Space Flight Simulator and Train Simulator Classic.
-- v2: d3d9/tests: Add Direct3DCreate9On12() tests. d3d9: Implement Direct3DCreate9On12().
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- include/Makefile.in | 1 + include/d3d9on12.h | 84 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 include/d3d9on12.h
diff --git a/include/Makefile.in b/include/Makefile.in index f70aeb9414b..805188e5f17 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -138,6 +138,7 @@ SOURCES = \ d3d8types.h \ d3d9.h \ d3d9caps.h \ + d3d9on12.h \ d3d9types.h \ d3dcaps.h \ d3dcommon.idl \ diff --git a/include/d3d9on12.h b/include/d3d9on12.h new file mode 100644 index 00000000000..72293f439bd --- /dev/null +++ b/include/d3d9on12.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _WINE_D3D9ON12_H_ +#define _WINE_D3D9ON12_H_ + +#include "d3d9.h" +#include "d3d12.h" + +#define MAX_D3D9ON12_QUEUES 2 + +typedef struct D3D9ON12_ARGS +{ + BOOL Enable9On12; + IUnknown *pD3D12Device; + IUnknown *ppD3D12Queues[MAX_D3D9ON12_QUEUES]; + UINT NumQueues; + UINT NodeMask; +} D3D9ON12_ARGS; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef IDirect3D9 * (__stdcall *PFN_Direct3DCreate9On12)(UINT sdk_version, D3D9ON12_ARGS *override_list, UINT override_entries); +IDirect3D9 * __stdcall Direct3DCreate9On12(UINT,D3D9ON12_ARGS *,UINT); + +DEFINE_GUID(IID_IDirect3DDevice9On12, 0xe7fda234, 0xb589, 0x4049, 0x94, 0x0d, 0x88, 0x78, 0x97, 0x75, 0x31, 0xc8); +typedef struct IDirect3DDevice9On12 *LPDIRECT3DDEVICE9ON12, *PDIRECT3DDEVICE9ON12; + +#undef INTERFACE +#define INTERFACE IDirect3DDevice9On12 +DECLARE_INTERFACE_(IDirect3DDevice9On12, IUnknown) +{ + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + /* IDirect3DDevice9On12 methods */ + STDMETHOD(GetD3D12Device)(THIS_ REFIID riid, void **out) PURE; + STDMETHOD(UnwrapUnderlyingResource)(THIS_ IDirect3DResource9 *resource, ID3D12CommandQueue *queue, REFIID riid, void **out) PURE; + STDMETHOD(ReturnUnderlyingResource)(THIS_ IDirect3DResource9 *resource, UINT num_sync, UINT64 *signal_values, ID3D12Fence **fences) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +/* IUnknown methods */ +#define IDirect3DDevice9On12_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DDevice9On12_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DDevice9On12_Release(p) (p)->lpVtbl->Release(p) +/* IDirect3DDevice9On12 methods */ +#define IDirect3DDevice9On12_GetD3D12Device(p,a,b) (p)->lpVtbl->GetD3D12Device(p,a,b) +#define IDirect3DDevice9On12_UnwrapUnderlyingResource(p,a,b,c,d) (p)->lpVtbl->UnwrapUnderlyingResource(p,a,b,c,d) +#define IDirect3DDevice9On12_ReturnUnderlyingResource(p,a,b,c,d) (p)->lpVtbl->ReturnUnderlyingResource(p,a,b,c,d) +#else +/* IUnknown methods */ +#define IDirect3DDevice9On12_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirect3DDevice9On12_AddRef(p) (p)->AddRef() +#define IDirect3DDevice9On12_Release(p) (p)->Release() +/* IDirect3DDevice9On12 methods */ +#define IDirect3DDevice9On12_GetD3D12Device(p,a,b) (p)->GetD3D12Device(a,b) +#define IDirect3DDevice9On12_UnwrapUnderlyingResource(p,a,b,c,d) (p)->UnwrapUnderlyingResource(a,b,c,d) +#define IDirect3DDevice9On12_ReturnUnderlyingResource(p,a,b,c,d) (p)->ReturnUnderlyingResource(a,b,c,d) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _WINE_D3D9ON12_H_ */
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Needed by Orbiter Space Flight Simulator and Train Simulator Classic. --- dlls/d3d9/Makefile.in | 1 + dlls/d3d9/d3d9.spec | 1 + dlls/d3d9/d3d9_main.c | 29 ++++++++++ dlls/d3d9/d3d9_private.h | 11 ++++ dlls/d3d9/d3d9on12.c | 122 +++++++++++++++++++++++++++++++++++++++ dlls/d3d9/device.c | 18 ++++++ 6 files changed, 182 insertions(+) create mode 100644 dlls/d3d9/d3d9on12.c
diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in index 5a717b11863..84380258c32 100644 --- a/dlls/d3d9/Makefile.in +++ b/dlls/d3d9/Makefile.in @@ -5,6 +5,7 @@ IMPORTS = dxguid uuid wined3d SOURCES = \ buffer.c \ d3d9_main.c \ + d3d9on12.c \ device.c \ directx.c \ query.c \ diff --git a/dlls/d3d9/d3d9.spec b/dlls/d3d9/d3d9.spec index a33cba51e77..11ad26b64c6 100644 --- a/dlls/d3d9/d3d9.spec +++ b/dlls/d3d9/d3d9.spec @@ -12,3 +12,4 @@ @ stdcall DebugSetMute() @ stdcall Direct3DCreate9(long) @ stdcall Direct3DCreate9Ex(long ptr) +@ stdcall Direct3DCreate9On12(long ptr long) diff --git a/dlls/d3d9/d3d9_main.c b/dlls/d3d9/d3d9_main.c index 5bdf05409aa..5f0c177eedd 100644 --- a/dlls/d3d9/d3d9_main.c +++ b/dlls/d3d9/d3d9_main.c @@ -75,6 +75,35 @@ HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9E return D3D_OK; }
+IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9On12(UINT sdk_version, D3D9ON12_ARGS *override_list, UINT override_entries) +{ + struct d3d9 *object; + + TRACE("sdk_version %#x, override_list %p, override_entries %#x.\n", sdk_version, override_list, override_entries); + + if (!(object = calloc(1, sizeof(*object)))) + return NULL; + + if (!d3d9_init(object, TRUE)) + { + WARN("Failed to initialize d3d9.\n"); + free(object); + return NULL; + } + if (!d3d9on12_init(&object->d3d9on12, override_list, override_entries)) + { + WARN("Failed to initialize d3d9on12.\n"); + free(object->d3d9on12); + return NULL; + } + SetLastError(ERROR_SUCCESS); + + TRACE("Created d3d9 object %p.\n", object); + if (object->d3d9on12) TRACE("Created d3d9on12 object %p.\n", object->d3d9on12); + + return (IDirect3D9 *)&object->IDirect3D9Ex_iface; +} + /* The callback is called on any error encountered during validation, including * improper IDirect3DShaderValidator9 method calls. * - "file" and "line" are passed through directly from Instruction(). "line" diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index a5f059c5aef..fd782f0eb47 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -34,6 +34,7 @@ #include "wine/debug.h"
#include "d3d9.h" +#include "d3d9on12.h" #include "wine/wined3d.h"
#define D3D9_MAX_VERTEX_SHADER_CONSTANTF 256 @@ -57,10 +58,19 @@ unsigned int wined3dmapflags_from_d3dmapflags(unsigned int flags, unsigned int u void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters, const struct wined3d_swapchain_desc *swapchain_desc, DWORD presentation_interval);
+struct d3d9on12 +{ + IDirect3DDevice9On12 IDirect3DDevice9On12_iface; + LONG refcount; + struct D3D9ON12_ARGS *override_list; + UINT override_entries; +}; + struct d3d9 { IDirect3D9Ex IDirect3D9Ex_iface; LONG refcount; + struct d3d9on12 *d3d9on12; struct wined3d *wined3d; struct wined3d_output **wined3d_outputs; unsigned int wined3d_output_count; @@ -70,6 +80,7 @@ struct d3d9 void d3d9_caps_from_wined3dcaps(const struct d3d9 *d3d9, unsigned int adapter_ordinal, D3DCAPS9 *caps, const struct wined3d_caps *wined3d_caps); BOOL d3d9_init(struct d3d9 *d3d9, BOOL extended); +BOOL d3d9on12_init(struct d3d9on12 **d3d9on12, D3D9ON12_ARGS *override_list, UINT override_entries);
struct fvf_declaration { diff --git a/dlls/d3d9/d3d9on12.c b/dlls/d3d9/d3d9on12.c new file mode 100644 index 00000000000..89ff0ffb55c --- /dev/null +++ b/dlls/d3d9/d3d9on12.c @@ -0,0 +1,122 @@ +/* + * IDirect3DDevice9On12 implementation + * + * Copyright (C) 2024 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "d3d9_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d9); + +static inline struct d3d9on12 *impl_from_IDirect3DDevice9On12( IDirect3DDevice9On12 *iface ) +{ + return CONTAINING_RECORD( iface, struct d3d9on12, IDirect3DDevice9On12_iface ); +} + +static HRESULT WINAPI d3d9on12_QueryInterface( IDirect3DDevice9On12 *iface, REFIID iid, void **out ) +{ + struct d3d9on12 *d3d9on12 = impl_from_IDirect3DDevice9On12(iface); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IDirect3DDevice9On12 )) + { + IDirect3DDevice9On12_AddRef( &d3d9on12->IDirect3DDevice9On12_iface ); + *out = &d3d9on12->IDirect3DDevice9On12_iface; + return S_OK; + } + + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI d3d9on12_AddRef( IDirect3DDevice9On12 *iface ) +{ + struct d3d9on12 *d3d9on12 = impl_from_IDirect3DDevice9On12(iface); + ULONG refcount = InterlockedIncrement(&d3d9on12->refcount); + TRACE( "%p increasing refcount to %lu.\n", iface, refcount ); + return refcount; +} + +static ULONG WINAPI d3d9on12_Release( IDirect3DDevice9On12 *iface ) +{ + struct d3d9on12 *d3d9on12 = impl_from_IDirect3DDevice9On12(iface); + ULONG refcount = InterlockedDecrement(&d3d9on12->refcount); + TRACE( "%p decreasing refcount to %lu.\n", iface, refcount ); + if (!refcount) + { + free( d3d9on12->override_list ); + free( d3d9on12 ); + } + return refcount; +} + +static HRESULT WINAPI d3d9on12_GetD3D12Device( IDirect3DDevice9On12 *iface, REFIID iid, void **out ) +{ + FIXME( "iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out ); + if (out) *out = NULL; + return S_OK; +} + +static HRESULT WINAPI d3d9on12_UnwrapUnderlyingResource( IDirect3DDevice9On12 *iface, IDirect3DResource9 *resource, ID3D12CommandQueue *queue, REFIID iid, void **out ) +{ + FIXME( "iface %p, resource %p, queue %p, iid %s, out %p stub!\n", iface, resource, queue, debugstr_guid(iid), out ); + return E_NOTIMPL; +} + +static HRESULT WINAPI d3d9on12_ReturnUnderlyingResource( IDirect3DDevice9On12 *iface, IDirect3DResource9 *resource, UINT num_sync, UINT64 *signal_values, ID3D12Fence **fences ) +{ + FIXME( "iface %p, resource %p, num_sync %#x, signal_values %p, fences %p stub!\n", iface, resource, num_sync, signal_values, fences ); + return E_NOTIMPL; +} + +static const struct IDirect3DDevice9On12Vtbl d3d9on12_vtbl = +{ + /* IUnknown */ + d3d9on12_QueryInterface, + d3d9on12_AddRef, + d3d9on12_Release, + /* IDirect3DDevice9On12 */ + d3d9on12_GetD3D12Device, + d3d9on12_UnwrapUnderlyingResource, + d3d9on12_ReturnUnderlyingResource, +}; + +BOOL d3d9on12_init( struct d3d9on12 **d3d9on12, D3D9ON12_ARGS *override_list, UINT override_entries ) +{ + struct d3d9on12 *object; + + if (!override_entries || !override_list->Enable9On12) + { + *d3d9on12 = NULL; + return TRUE; + } + + if (!(object = calloc(1, sizeof(*object)))) + return FALSE; + + object->IDirect3DDevice9On12_iface.lpVtbl = &d3d9on12_vtbl; + object->refcount = 1; + object->override_list = override_list; + object->override_entries = override_entries; + + *d3d9on12 = object; + return TRUE; +} diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 1267dc8fca1..669bc8845f5 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -623,6 +623,24 @@ static HRESULT WINAPI d3d9_device_QueryInterface(IDirect3DDevice9Ex *iface, REFI return S_OK; }
+ if (IsEqualGUID(riid, &IID_IDirect3DDevice9On12)) + { + struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); + + if (!device->d3d_parent->d3d9on12) + { + WARN("IDirect3D9 instance wasn't created with D3D9On12 enabled, returning E_NOINTERFACE %p.\n", device->d3d_parent->d3d9on12); + *out = NULL; + return E_NOINTERFACE; + } + + FIXME("pD3D12Device value is not being checked if it matches the d3d9 device\n"); + + IDirect3DDevice9On12_AddRef(iface); + *out = &device->d3d_parent->d3d9on12->IDirect3DDevice9On12_iface; + return S_OK; + } + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
*out = NULL;
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/d3d9/tests/Makefile.in | 2 +- dlls/d3d9/tests/d3d9ex.c | 252 ++++++++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+), 1 deletion(-)
diff --git a/dlls/d3d9/tests/Makefile.in b/dlls/d3d9/tests/Makefile.in index 17d0a451fbc..b2afdd119a9 100644 --- a/dlls/d3d9/tests/Makefile.in +++ b/dlls/d3d9/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = d3d9.dll -IMPORTS = d3d9 user32 gdi32 +IMPORTS = d3d9 d3d12 dxgi user32 gdi32
SOURCES = \ d3d9ex.c \ diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c index 8e7eec13566..9213b785734 100644 --- a/dlls/d3d9/tests/d3d9ex.c +++ b/dlls/d3d9/tests/d3d9ex.c @@ -25,11 +25,16 @@ #include "wine/test.h" #include <initguid.h> #include <d3d9.h> +#include <d3d9on12.h> +#include <dxgi1_6.h>
static HMODULE d3d9_handle = 0; static DEVMODEW registry_mode;
static HRESULT (WINAPI *pDirect3DCreate9Ex)(UINT SDKVersion, IDirect3D9Ex **d3d9ex); +static IDirect3D9 * (WINAPI *pDirect3DCreate9On12)(UINT sdk_version, D3D9ON12_ARGS *override_list, UINT override_entries); + +DEFINE_GUID(IID_IDeadbeef, 0xdeadbeef, 0xdead, 0xbeef, 0xde, 0xad, 0xbe, 0xef, 0x11, 0x11, 0x11, 0x11);
#define CREATE_DEVICE_FULLSCREEN 0x01 #define CREATE_DEVICE_NOWINDOWCHANGES 0x02 @@ -5058,6 +5063,252 @@ static void test_desktop_window(void) IDirect3DDevice9Ex_Release(device); }
+static void reset_d3d9on12_args(D3D9ON12_ARGS *override_list) +{ + memset(override_list, 0, sizeof(*override_list)); + override_list->Enable9On12 = FALSE; + override_list->pD3D12Device = NULL; + memset(override_list->ppD3D12Queues, 0, sizeof(override_list->ppD3D12Queues)); + override_list->NumQueues = 0; + override_list->NodeMask = 0; +} + +#define create_d3d9on12_device(out_d3d9, window, override_list, override_entries, out_device) \ + create_d3d9on12_device_(__LINE__, out_d3d9, window, override_list, override_entries, out_device) +static HRESULT create_d3d9on12_device_(unsigned int line, IDirect3D9 **out_d3d9, HWND window, D3D9ON12_ARGS *override_list, + UINT override_entries, IDirect3DDevice9 **out_device) +{ + IDirect3DDevice9On12 *d3d9on12 = (void *)0xdeadbeef; + IDirect3DDevice9 *device = (void *)0xdeadbeef; + IDirect3D9 *d3d9 = (void *)0xdeadbeef; + D3DPRESENT_PARAMETERS present_parameters; + HRESULT hr; + + memset(&present_parameters, 0, sizeof(present_parameters)); + present_parameters.Windowed = TRUE; + present_parameters.hDeviceWindow = window; + present_parameters.SwapEffect = D3DSWAPEFFECT_COPY; + present_parameters.BackBufferWidth = 640; + present_parameters.BackBufferHeight = 480; + present_parameters.EnableAutoDepthStencil = FALSE; + present_parameters.AutoDepthStencilFormat = D3DFMT_D16; + + SetLastError(0xdeadbeef); + d3d9 = pDirect3DCreate9On12(D3D_SDK_VERSION, override_list, override_entries); + ok_(__FILE__, line)(d3d9 != NULL, "got NULL d3d9 object\n"); + ok_(__FILE__, line)(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == ERROR_TOO_MANY_POSTS), + "Direct3DCreate9On12 GetLastError returned %#lx\n", GetLastError()); + + hr = IDirect3D9_QueryInterface(d3d9, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok_(__FILE__, line)(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok_(__FILE__, line)(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + + hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, present_parameters.hDeviceWindow, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device); + + *out_d3d9 = d3d9; + *out_device = device; + + return hr; +} + +static void test_d3d9on12(void) +{ + IDirect3DDevice9On12 *d3d9on12_2 = (void *)0xdeadbeef; + IDirect3DDevice9On12 *d3d9on12 = (void *)0xdeadbeef; + IDirect3DDevice9 *device = (void *)0xdeadbeef; + IDirect3D9 *d3d9 = (void *)0xdeadbeef; + IDXGIAdapter *adapter = (void *)0xdeadbeef; + IDXGIFactory4 *factory = (void *)0xdeadbeef; + ID3D12Device *d3d12device = (void *)0xdeadbeef; + ID3D12Device *d3d12device_2 = (void *)0xdeadbeef; + HWND window = create_window(); + D3D9ON12_ARGS override_list; + UINT override_entries = 0; + HRESULT hr; + + pDirect3DCreate9On12 = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9On12"); + if (!pDirect3DCreate9On12) + { + win_skip("Direct3DCreate9On12 is not supported, skipping d3d9on12 tests\n"); + return; + } + + reset_d3d9on12_args(&override_list); + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + if (0) /* Crashes under Windows */ + { + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_list.NumQueues = MAX_D3D9ON12_QUEUES; + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_list.NumQueues = 1; + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + } + + reset_d3d9on12_args(&override_list); + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_list.NodeMask = 0xdeadbeef; + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_Release(d3d9on12_2); + IDirect3DDevice9On12_Release(d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_Release(d3d9on12_2); + IDirect3DDevice9On12_Release(d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_entries = 0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_Release(d3d9on12_2); + IDirect3DDevice9On12_Release(d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IDXGIFactory4_EnumAdapters(factory, 0, &adapter); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDXGIFactory4_Release(factory); + + hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&d3d12device); + IDXGIAdapter_Release(adapter); + + reset_d3d9on12_args(&override_list); + override_list.Enable9On12 = TRUE; + override_list.pD3D12Device = (IUnknown *)d3d12device; + override_entries = 1; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device); + if (FAILED(hr)) + { + skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n"); + goto out; + } + + hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IDirect3DDevice9On12_GetD3D12Device(d3d9on12, NULL, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_GetD3D12Device(d3d9on12, &IID_ID3D12Device, (void **)&d3d12device_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine + ok(override_list.pD3D12Device == (IUnknown *)d3d12device_2, "GetD3D12Device returned device %p, expected %p\n", d3d12device_2, override_list.pD3D12Device); + d3d12device_2 = (void *)0xdeadbeef; + IDirect3DDevice9On12_GetD3D12Device(d3d9on12, &IID_IDeadbeef, (void **)&d3d12device_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(d3d12device_2 == NULL, "GetD3D12Device returned device %p, expected NULL\n", d3d12device_2); + + IDirect3DDevice9On12_Release(d3d9on12_2); + IDirect3DDevice9On12_Release(d3d9on12); + IDirect3DDevice9_Release(device); +out: + IDirect3D9_Release(d3d9); + DestroyWindow(window); +} + START_TEST(d3d9ex) { DEVMODEW current_mode; @@ -5118,6 +5369,7 @@ START_TEST(d3d9ex) test_sysmem_draw(); test_pinned_buffers(); test_desktop_window(); + test_d3d9on12();
UnregisterClassA("d3d9_test_wc", GetModuleHandleA(NULL)); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=142358
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
d3d9: 1e10:visual: unhandled exception c0000005 at 00007FFA26C6C1F4
=== debian11b (64 bit WoW report) ===
comctl32: button.c:801: Test failed: [0] expected uItemState 16, got 80 button.c:801: Test failed: [0] expected uItemState 16, got 80 button.c:810: Test failed: [0] expected uItemState 0, got 64 button.c:810: Test failed: [0] expected uItemState 0, got 64 button.c:819: Test failed: [0] expected uItemState 0, got 64 button.c:819: Test failed: [0] expected uItemState 0, got 64 button.c:834: Test failed: expected state 0, got 0200 button.c:838: Test failed: [0] expected uItemState 1, got 65 button.c:838: Test failed: [0] expected uItemState 1, got 65 button.c:847: Test failed: expected state 0x0004, got 0204 button.c:854: Test failed: [0] expected uItemState 0, got 64 button.c:854: Test failed: [0] expected uItemState 0, got 64 button.c:863: Test failed: expected state 0, got 0200 button.c:898: Test failed: [0] expected uItemState 0, got 64 button.c:898: Test failed: [0] expected uItemState 0, got 64 button.c:898: Test failed: [0] expected uItemState 0, got 64 button.c:898: Test failed: [0] expected uItemState 0, got 64
On Thu Jan 25 08:15:22 2024 +0000, Nikolay Sivov wrote:
I don't know what ARGS are supposed to do exactly, but the way it's handled does not make a lot of sense to me.
Since a D3D12Device is not being created I don't think it really matters for now.
On Thu Jan 25 08:15:35 2024 +0000, Matteo Bruni wrote:
Here we should check that the pD3D12Device value matches with the one used by this d3d9 device. It might be okay if we don't for now but at least a FIXME is necessary.
I'm assuming the D3D12Device is created when `IDirect3DDevice9On12::GetD3D12Device()` is called, otherwise I don't know how to check this. I've added a FIXME for now.
On Thu Jan 25 08:12:07 2024 +0000, Mohamad Al-Jaf wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4915/diffs?diff_id=95801&start_sha=564c1d553d8b9e6106a1892d087a80ccbbac6e87#c8180f1af3a2002cac093549386154a247853453_5101_5210)
I'm assuming you meant the entire line because leaving `IDirect3DDevice9On12_Release(d3d9on12);` causes it to crash.
On Thu Jan 25 08:16:13 2024 +0000, Matteo Bruni wrote:
We want to test the Enable9On12 == TRUE, pD3D12Device == NULL case as well. Generally extending the tests some more would be nice.
Thanks for the thorough and clear feedback. :slight_smile:
I've added a few more tests. Not sure how redundant some of them are.
On Thu Jan 25 08:15:58 2024 +0000, Mohamad Al-Jaf wrote:
I'm assuming you meant the entire line because leaving `IDirect3DDevice9On12_Release(d3d9on12);` causes it to crash.
It only causes a crash if the previous ok() fails, which we don't want. Tests should always pass, if they don't you have to fix them (possibly by using todo_wine).
On Thu Jan 25 11:39:52 2024 +0000, Matteo Bruni wrote:
It only causes a crash if the previous ok() fails, which we don't want. Tests should always pass, if they don't you have to fix them (possibly by using todo_wine).
Scratch that, that ok() passes if d3d9on12 is NULL, so yeah I did mean the whole line :sweat_smile:
On Thu Jan 25 12:54:52 2024 +0000, Mohamad Al-Jaf wrote:
Since a D3D12Device is not being created I don't think it really matters for now.
What matters is that you store a user pointer.
On Thu Jan 25 12:54:52 2024 +0000, Nikolay Sivov wrote:
What matters is that you store a user pointer.
Good catch Nikolay. You should e.g. copy the contents to a heap allocated area or something like that.
Nikolay Sivov (@nsivov) commented about dlls/d3d9/tests/d3d9ex.c:
reset_d3d9on12_args(&override_list);
override_list.Enable9On12 = TRUE;
override_list.NumQueues = 1;
override_entries = 1;
hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device);
if (FAILED(hr))
{
skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n");
goto out;
}
hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12);
ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12);
IDirect3DDevice9_Release(device);
IDirect3D9_Release(d3d9);
- }
If something crashes there, why bother with skipping.
Nikolay Sivov (@nsivov) commented about dlls/d3d9/tests/Makefile.in:
TESTDLL = d3d9.dll -IMPORTS = d3d9 user32 gdi32 +IMPORTS = d3d9 d3d12 dxgi user32 gdi32
I don't think we want to import it.
On Thu Jan 25 12:57:31 2024 +0000, Matteo Bruni wrote:
Good catch Nikolay. You should e.g. copy the contents to a heap allocated area or something like that.
Or maybe you shouldn't, if you don't need them later.
On Thu Jan 25 12:59:47 2024 +0000, Nikolay Sivov wrote:
Or maybe you shouldn't, if you don't need them later.
It would be used in place of the `FIXME()` in `d3d9_device_QueryInterface()`. Dunno, it doesn't seem too terrible to store it for now, even if it isn't used yet. Not that I'm opposed to implementing that part right away either.
On Thu Jan 25 12:59:16 2024 +0000, Nikolay Sivov wrote:
I don't think we want to import it.
Fair enough. It would be preferable to dynamically link to dxgi and d3d12 (i.e. via LoadLibrary() and GetProcAddress()).
Matteo Bruni (@Mystral) commented about dlls/d3d9/tests/d3d9ex.c:
IDirect3DDevice9Ex_Release(device);
}
+static void reset_d3d9on12_args(D3D9ON12_ARGS *override_list) +{
- memset(override_list, 0, sizeof(*override_list));
- override_list->Enable9On12 = FALSE;
- override_list->pD3D12Device = NULL;
- memset(override_list->ppD3D12Queues, 0, sizeof(override_list->ppD3D12Queues));
- override_list->NumQueues = 0;
- override_list->NodeMask = 0;
+}
The initial memset should be enough, right?
Matteo Bruni (@Mystral) commented about dlls/d3d9/tests/d3d9ex.c:
- ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
- ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12);
- IDirect3DDevice9_Release(device);
- IDirect3D9_Release(d3d9);
- reset_d3d9on12_args(&override_list);
- override_list.Enable9On12 = TRUE;
- hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device);
- if (FAILED(hr))
- {
skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n");
goto out;
- }
- hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12);
- ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
- ok(d3d9on12 == NULL, "QueryInterface returned interface %p, expected NULL\n", d3d9on12);
Not that I'd expect any surprise, but `d3d9on12` should be reset to 0xdeadbeef before the `QueryInterface()` call, to make sure that's again been set to NULL.
Matteo Bruni (@Mystral) commented about dlls/d3d9/tests/d3d9ex.c:
- reset_d3d9on12_args(&override_list);
- override_list.Enable9On12 = TRUE;
- override_list.pD3D12Device = (IUnknown *)d3d12device;
- override_entries = 1;
- hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device);
- if (FAILED(hr))
- {
skip("Failed to create a regular Direct3DDevice9, skipping d3d9on12 tests\n");
goto out;
- }
- hr = IDirect3DDevice9_QueryInterface(device, &IID_IDirect3DDevice9On12, (void **)&d3d9on12);
- ok(hr == S_OK, "Got hr %#lx.\n", hr);
- IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2);
- ok(hr == S_OK, "Got hr %#lx.\n", hr);
I'm not sure what's the deal with this double QI on the d3d9 object (here and in the previous tests). It doesn't seem to add anything of value.
I don't know if the maintainers agree, but I'd put the new tests in a separate file, because D3D9Ex refers to something specific. Maybe renaming d3d9ex.c to something more generic would also work.
Do these applications need a complete implementation?