Needed by Orbiter Space Flight Simulator and Train Simulator Classic.
-- v12: d3d9/tests: Add Direct3DCreate9On12() tests. d3d9: Implement Direct3DCreate9On12(). include: Add d3d9on12.idl file.
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- include/Makefile.in | 1 + include/d3d9on12.idl | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 include/d3d9on12.idl
diff --git a/include/Makefile.in b/include/Makefile.in index c527a17cec4..0145fe4a7d7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -138,6 +138,7 @@ SOURCES = \ d3d8types.h \ d3d9.h \ d3d9caps.h \ + d3d9on12.idl \ d3d9types.h \ d3dcaps.h \ d3dcommon.idl \ diff --git a/include/d3d9on12.idl b/include/d3d9on12.idl new file mode 100644 index 00000000000..9eec402a711 --- /dev/null +++ b/include/d3d9on12.idl @@ -0,0 +1,50 @@ +/* + * 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 + */ + +cpp_quote("#include <d3d9.h>") +import "d3d12.idl"; + +interface IDirect3D9; +interface IDirect3DResource9; + +#define MAX_D3D9ON12_QUEUES 2 + +typedef struct D3D9ON12_ARGS +{ + BOOL Enable9On12; + IUnknown *pD3D12Device; + IUnknown *ppD3D12Queues[MAX_D3D9ON12_QUEUES]; + UINT NumQueues; + UINT NodeMask; +} D3D9ON12_ARGS; + +typedef IDirect3D9 * (__stdcall *PFN_Direct3DCreate9On12)(UINT sdk_version, D3D9ON12_ARGS *override_list, UINT override_entries); +IDirect3D9 * __stdcall Direct3DCreate9On12(UINT,D3D9ON12_ARGS *,UINT); + +typedef struct IDirect3DDevice9On12 *LPDIRECT3DDEVICE9ON12, *PDIRECT3DDEVICE9ON12; + +[ + local, + uuid(e7fda234-b589-4049-940d-8878977531c8) +] +interface IDirect3DDevice9On12 : IUnknown +{ + HRESULT GetD3D12Device (REFIID riid, void **out); + HRESULT UnwrapUnderlyingResource (IDirect3DResource9 *resource, ID3D12CommandQueue *queue, REFIID riid, void **out); + HRESULT ReturnUnderlyingResource (IDirect3DResource9 *resource, UINT num_sync, UINT64 *signal_values, ID3D12Fence **fences); +}
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/d3d9/tests/device.c | 276 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+)
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 9d92b248dd9..7361d00d517 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -25,6 +25,19 @@ #define COBJMACROS #include <d3d9.h> #include "utils.h" +#include <initguid.h> +#include <d3d9on12.h> +#include <dxgi1_4.h> + +static HMODULE d3d9_handle = 0; +static HMODULE d3d12_handle = 0; +static HMODULE dxgi_handle = 0; + +static IDirect3D9 * (WINAPI *pDirect3DCreate9On12)(UINT sdk_version, D3D9ON12_ARGS *override_list, UINT override_entries); +static HRESULT (WINAPI *pCreateDXGIFactory2)(UINT flags, REFIID iid, void **factory); +static HRESULT (WINAPI *pD3D12CreateDevice)(IUnknown *adapter, D3D_FEATURE_LEVEL feature_level, REFIID iid, void **device); + +DEFINE_GUID(IID_IDeadbeef, 0xdeadbeef, 0xdead, 0xbeef, 0xde, 0xad, 0xbe, 0xee, 0xee, 0xee, 0xee, 0xef);
struct vec3 { @@ -15027,6 +15040,268 @@ static void test_window_position(void) IDirect3D9_Release(d3d); }
+static BOOL init_d3d9on12_modules(void) +{ + d3d9_handle = LoadLibraryA("d3d9.dll"); + if (!d3d9_handle) + { + skip("Could not load d3d9.dll\n"); + return FALSE; + } + dxgi_handle = LoadLibraryA("dxgi.dll"); + if (!dxgi_handle) + { + skip("Could not load dxgi.dll\n"); + return FALSE; + } + d3d12_handle = LoadLibraryA("d3d12.dll"); + if (!d3d12_handle) + { + skip("Could not load d3d12.dll\n"); + return FALSE; + } + + pDirect3DCreate9On12 = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9On12"); + if (!pDirect3DCreate9On12) + { + win_skip("Direct3DCreate9On12 is not supported, skipping d3d9on12 tests\n"); + return FALSE; + } + pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_handle, "CreateDXGIFactory2"); + if (!pCreateDXGIFactory2) + { + win_skip("CreateDXGIFactory2 is not supported, skipping d3d9on12 tests\n"); + return FALSE; + } + pD3D12CreateDevice = (void *)GetProcAddress(d3d12_handle, "D3D12CreateDevice"); + if (!pD3D12CreateDevice) + { + win_skip("D3D12CreateDevice is not supported, skipping d3d9on12 tests\n"); + return FALSE; + } + + return TRUE; +} + +#define create_d3d9on12_device(out_d3d9, window, override_list, override_entries, out_device, success) \ + create_d3d9on12_device_(__LINE__, out_d3d9, window, override_list, override_entries, out_device, success) +static HRESULT create_d3d9on12_device_(unsigned int line, IDirect3D9 **out_d3d9, HWND window, D3D9ON12_ARGS *override_list, + UINT override_entries, IDirect3DDevice9 **out_device, BOOLEAN success) +{ + 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"); + if (success) + ok_(__FILE__, line)(GetLastError() == ERROR_SUCCESS, "Direct3DCreate9On12 GetLastError returned %#lx\n", GetLastError()); + else + ok_(__FILE__, line)(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; + D3D9ON12_ARGS override_list; + UINT override_entries = 0; + ULONG ref; + HRESULT hr; + HWND window = CreateWindowA("d3d9_test_wc", "d3d9_test", WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION, + 0, 0, 640, 480, 0, 0, 0, 0); + + if(!init_d3d9on12_modules()) + { + skip("Failed to load d3d9on12 modules, skipping d3d9on12 tests.\n"); + return; + } + + SetLastError(0xdeadbeef); + d3d9 = pDirect3DCreate9On12(D3D_SDK_VERSION, NULL, override_entries); + ok(d3d9 != NULL, "got NULL d3d9 object\n"); + ok(GetLastError() == ERROR_TOO_MANY_POSTS, "Direct3DCreate9On12 GetLastError returned %#lx\n", GetLastError()); + IDirect3D9_Release(d3d9); + + memset(&override_list, 0, sizeof(override_list)); + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, FALSE); + 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); + + memset(&override_list, 0, sizeof(override_list)); + override_list.Enable9On12 = TRUE; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, FALSE); + 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); + ref = IDirect3DDevice9_Release(device); + ok(ref == 0, "Got refcount %lu.\n", ref); + IDirect3D9_Release(d3d9); + + memset(&override_list, 0, sizeof(override_list)); + override_entries = 1; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, FALSE); + 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); + ref = IDirect3DDevice9_Release(device); + ok(ref == 0, "Got refcount %lu.\n", ref); + IDirect3D9_Release(d3d9); + + memset(&override_list, 0, sizeof(override_list)); + override_list.Enable9On12 = TRUE; + override_list.NodeMask = 0xdeadbeef; + override_entries = 1; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, TRUE); + 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); + hr = IDirect3DDevice9On12_QueryInterface(d3d9on12, &IID_IDirect3DDevice9On12, (void **)&d3d9on12_2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ref = IDirect3DDevice9On12_Release(d3d9on12_2); + ok(ref == 1, "Got refcount %lu.\n", ref); + ref = IDirect3DDevice9On12_Release(d3d9on12); + ok(ref == 0, "Got refcount %lu.\n", ref); + ref = IDirect3DDevice9_Release(device); + ok(ref == 0, "Got refcount %lu.\n", ref); + IDirect3D9_Release(d3d9); + + memset(&override_list, 0, sizeof(override_list)); + override_list.Enable9On12 = TRUE; + override_entries = 1; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, TRUE); + 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); + hr = IDirect3DDevice9On12_GetD3D12Device(d3d9on12, NULL, NULL); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = IDirect3DDevice9On12_GetD3D12Device(d3d9on12, &IID_IDeadbeef, NULL); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + IDirect3DDevice9On12_Release(d3d9on12); + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d9); + + memset(&override_list, 0, sizeof(override_list)); + override_list.Enable9On12 = TRUE; + override_entries = 0xdeadbeef; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, TRUE); + 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); + ref = IDirect3DDevice9On12_Release(d3d9on12); + ok(ref == 0, "Got refcount %lu.\n", ref); + ref = IDirect3DDevice9_Release(device); + ok(ref == 0, "Got refcount %lu.\n", ref); + IDirect3D9_Release(d3d9); + + hr = pCreateDXGIFactory2(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 = pD3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&d3d12device); + IDXGIAdapter_Release(adapter); + + memset(&override_list, 0, sizeof(override_list)); + override_list.Enable9On12 = TRUE; + override_list.pD3D12Device = (IUnknown *)d3d12device; + override_entries = 1; + d3d9on12 = (void *)0xdeadbeef; + hr = create_d3d9on12_device(&d3d9, window, &override_list, override_entries, &device, TRUE); + 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); + + hr = IDirect3DDevice9On12_GetD3D12Device(d3d9on12, &IID_ID3D12Device, (void **)&d3d12device_2); + todo_wine + 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; + hr = IDirect3DDevice9On12_GetD3D12Device(d3d9on12, &IID_IDeadbeef, (void **)&d3d12device_2); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); + ok(d3d12device_2 == NULL, "GetD3D12Device returned device %p, expected NULL\n", d3d12device_2); + + ref = IDirect3DDevice9On12_Release(d3d9on12); + ok(ref == 0, "Got refcount %lu.\n", ref); + ref = IDirect3DDevice9_Release(device); + ok(ref == 0, "Got refcount %lu.\n", ref); +out: + IDirect3D9_Release(d3d9); + DestroyWindow(window); +} + START_TEST(device) { HMODULE d3d9_handle = GetModuleHandleA("d3d9.dll"); @@ -15163,6 +15438,7 @@ START_TEST(device) test_creation_parameters(); test_cursor_clipping(); test_window_position(); + 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=145114
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
d3d9: device.c:15153: Test failed: Direct3DCreate9On12 GetLastError returned 0 device.c:15157: Test failed: Direct3DCreate9On12 GetLastError returned 0 device.c:15172: Test failed: Direct3DCreate9On12 GetLastError returned 0 device.c:15188: Test failed: Direct3DCreate9On12 GetLastError returned 0
=== 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:859: Test failed: BM_SETSTATE/FALSE on a button: the msg sequence is not complete: expected 0000 - actual 0084 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
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 | 39 +++++++++++ dlls/d3d9/d3d9_private.h | 11 +++ dlls/d3d9/d3d9on12.c | 147 +++++++++++++++++++++++++++++++++++++++ dlls/d3d9/device.c | 17 +++++ 6 files changed, 216 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..08829464cbc 100644 --- a/dlls/d3d9/d3d9_main.c +++ b/dlls/d3d9/d3d9_main.c @@ -75,6 +75,45 @@ 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; + HRESULT hr; + + 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; + } + + hr = d3d9on12_init(&object->d3d9on12, override_list, override_entries); + + if (hr == E_OUTOFMEMORY) + { + WARN("Failed to initialize d3d9on12.\n"); + free(object); + return NULL; + } + else if (hr == S_OK) + { + SetLastError(ERROR_SUCCESS); + TRACE("Created d3d9on12 object %p.\n", object->d3d9on12); + } + else + { + SetLastError(ERROR_TOO_MANY_POSTS); + } + + TRACE("Created d3d9 object %p.\n", object); + 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..d7b94e747f1 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,11 +58,20 @@ 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 wined3d *wined3d; + struct d3d9on12 *d3d9on12; struct wined3d_output **wined3d_outputs; unsigned int wined3d_output_count; BOOL extended; @@ -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); +HRESULT 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..fc8bc4bc09b --- /dev/null +++ b/dlls/d3d9/d3d9on12.c @@ -0,0 +1,147 @@ +/* + * 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) + { + if (d3d9on12->override_list) + { + if (d3d9on12->override_list->pD3D12Device) + ID3D12Device_Release( (ID3D12Device *)d3d9on12->override_list->pD3D12Device ); + + for ( int i = 0; i < d3d9on12->override_list->NumQueues; i++ ) + { + if (d3d9on12->override_list->ppD3D12Queues[i]) + ID3D12CommandQueue_Release( (ID3D12CommandQueue *)d3d9on12->override_list->ppD3D12Queues[i] ); + } + + 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) return E_INVALIDARG; + + *out = NULL; + return E_NOINTERFACE; +} + +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, +}; + +HRESULT d3d9on12_init( struct d3d9on12 **d3d9on12, D3D9ON12_ARGS *override_list, UINT override_entries ) +{ + struct d3d9on12 *object; + + if (!override_entries || !override_list || !override_list->Enable9On12) + { + *d3d9on12 = NULL; + return E_INVALIDARG; + } + + if (!(object = calloc( 1, sizeof(*object) ))) + { + free( object ); + *d3d9on12 = NULL; + return E_OUTOFMEMORY; + } + + FIXME( "ignoring override_list %p\n", override_list ); + + object->IDirect3DDevice9On12_iface.lpVtbl = &d3d9on12_vtbl; + object->refcount = 0; + object->override_list = NULL; + object->override_entries = override_entries; + + *d3d9on12 = object; + return S_OK; +} diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 1267dc8fca1..525ebb37f90 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -623,6 +623,23 @@ 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.\n"); + *out = NULL; + return E_NOINTERFACE; + } + + FIXME("pD3D12Device value is not being checked if it matches the d3d9 device\n"); + + IDirect3DDevice9On12_QueryInterface(&device->d3d_parent->d3d9on12->IDirect3DDevice9On12_iface, riid, out); + return S_OK; + } + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
*out = NULL;
If it's queryable from the device and not the d3d9, it should be an interface on the device and not the d3d9.
Direct3DCreate9On12 returns IDirect3D9, not IDirect3DDevice9[Ex]. How would you handle the arguments? They need to be stored somewhere.
Also, I added a refcount test which shows struct d3d9on12 is its own object with its own refcount. I don't know how to add it to `struct d3d9_device` in Direct3DCreate9On12.
Also, what is that FIXME doing in QueryInterface()?
@Mystral said a FIXME is necessary https://gitlab.winehq.org/wine/wine/-/merge_requests/4915#note_58810
I can remove it if this is not the case.
On Mon Apr 15 19:04:05 2024 +0000, Elizabeth Figura wrote:
The only failing test is GetLastError() after Direct3DCreate9On12(). Do you see any indication that function is supposed to *reliably* set the last error? It's not mentioned in [1], and it'd be the first time I've ever seen a d3d API work that way. [1] https://microsoft.github.io/DirectX-Specs/d3d/TranslationLayerResourceIntero...
I took a look at it again and it reliably sets the last error each time it's called. I added a condition to separate the two errors. It always sets ERROR_SUCCESS when it creates a d3d9on12 object, otherwise it sets it to ERROR_TOO_MANY_POSTS, which is an odd error to set it to.
This is true for my VM and most of the testbot VMs, but not for the Windows 11 AMD nor NVIDIA ones. It looks like it's dependent on a dedicated GPU or at least a functioning GPU. It also might have been changed for Windows 11 only.
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.
Sorry, I don't understand what this means? Which d3d12 device are we matching against the d3d9 device?
If it's queryable from the device and not the d3d9, it should be an interface on the device and not the d3d9.
Direct3DCreate9On12 returns IDirect3D9, not IDirect3DDevice9[Ex]. How would you handle the arguments? They need to be stored somewhere.
Store the flag in the d3d9 structure. Again, see the way we handle IID_IDirect3DDevice9Ex in d3d9_device_QueryInterface().
Also, I added a refcount test which shows struct d3d9on12 is its own object with its own refcount. I don't know how to add it to `struct d3d9_device` in Direct3DCreate9On12.
You can implement a separate refcount without needing a separate object (just use a separate refcount field), although it's not clear we need to care.
I took a look at it again and it reliably sets the last error each time it's called. I added a condition to separate the two errors. It always sets ERROR_SUCCESS when it creates a d3d9on12 object, otherwise it sets it to ERROR_TOO_MANY_POSTS, which is an odd error to set it to.
That only necessarily means that the function calls something which clobbers the last error. If it's not documented to set the last error, and no program has been shown to depend on it, then I wouldn't test or implement that behaviour.
Store the flag in the d3d9 structure. Again, see the way we handle IID_IDirect3DDevice9Ex in d3d9_device_QueryInterface().
The flag is no problem, but the arguments won't be passed into the d3d9 device. Where would you store D3D9ON12_ARGS *override_list and UINT override_entries? UINT sdk_version doesn't seem to be used anyway so that's not a problem.
What would you do in Direct3DCreate9On12?
You can implement a separate refcount without needing a separate object (just use a separate refcount field), although it's not clear we need to care.
This doesn't make sense to me. Are there examples of objects with more than one refcount? D3D9on12 is only created if the right arguments are passed to Direct3DCreate9On12. And it can be released independently of IDirect3DDevice9 so it should have its own refcount. Also, wouldn't it be better from a memory management perspective to handle it as a separate object?
On Wed May 29 07:05:40 2024 +0000, Elizabeth Figura wrote:
I took a look at it again and it reliably sets the last error each
time it's called. I added a condition to separate the two errors. It always sets ERROR_SUCCESS when it creates a d3d9on12 object, otherwise it sets it to ERROR_TOO_MANY_POSTS, which is an odd error to set it to. That only necessarily means that the function calls something which clobbers the last error. If it's not documented to set the last error, and no program has been shown to depend on it, then I wouldn't test or implement that behaviour.
Okay, I'll remove it in the next push.
On Wed Apr 17 20:44:37 2024 +0000, Elizabeth Figura 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. Sorry, I don't understand what this means? Which d3d12 device are we matching against the d3d9 device?
@Mystral Do you have any input on this matter? Should the FIXME stay or be removed?
The flag is no problem, but the arguments won't be passed into the d3d9 device.
d3d9_device holds a pointer to the d3d object. Again, this is exactly the way things work for d3d9ex. You should be able to follow *exactly* the same model, and refer to that when confused.
Where would you store D3D9ON12_ARGS *override_list and UINT override_entries? UINT sdk_version doesn't seem to be used anyway so that's not a problem.
In the d3d9 object.
I'm also inclined to recommend a better name than "override_list". Yes, the Microsoft headers use it, but the Microsoft headers make a lot of poor choices.
What would you do in Direct3DCreate9On12?
You can implement a separate refcount without needing a separate object (just use a separate refcount field), although it's not clear we need to care.
This doesn't make sense to me. Are there examples of objects with more than one refcount?
Yes, but I don't think it's worth implementing unless we find an application that needs it.
D3D9on12 is only created if the right arguments are passed to Direct3DCreate9On12. And it can be released independently of IDirect3DDevice9 so it should have its own refcount. Also, wouldn't it be better from a memory management perspective to handle it as a separate object?
QueryInterface() is supposed to be symmetric. That means that neither "object" can be destroyed until the other is, which means that they're really just one object. From a memory management perspective, that implies one allocation.