Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38086 Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/d3dx9_36/shader.c | 231 +++++++++++++++++++++++++++++++++-- dlls/d3dx9_36/tests/shader.c | 50 ++++++++ 2 files changed, 273 insertions(+), 8 deletions(-)
diff --git a/dlls/d3dx9_36/shader.c b/dlls/d3dx9_36/shader.c index c59fc791ea..b5b345880b 100644 --- a/dlls/d3dx9_36/shader.c +++ b/dlls/d3dx9_36/shader.c @@ -2069,27 +2069,242 @@ HRESULT WINAPI D3DXGetShaderConstantTable(const DWORD *byte_code, ID3DXConstantT return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table); }
-HRESULT WINAPI D3DXCreateFragmentLinker(IDirect3DDevice9 *device, UINT size, ID3DXFragmentLinker **linker) +struct d3dx9_fragment_linker { - FIXME("device %p, size %u, linker %p: stub.\n", device, size, linker); + ID3DXFragmentLinker ID3DXFragmentLinker_iface; + LONG ref;
- if (linker) - *linker = NULL; + struct IDirect3DDevice9 *device; + DWORD flags; +}; + +static inline struct d3dx9_fragment_linker *impl_from_ID3DXFragmentLinker(ID3DXFragmentLinker *iface) +{ + return CONTAINING_RECORD(iface, struct d3dx9_fragment_linker, ID3DXFragmentLinker_iface); +} + +static HRESULT WINAPI d3dx9_fragment_linker_QueryInterface(ID3DXFragmentLinker *iface, REFIID riid, void **out) +{ + TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+ if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_ID3DXFragmentLinker)) + { + iface->lpVtbl->AddRef(iface); + *out = iface; + return D3D_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI d3dx9_fragment_linker_AddRef(ID3DXFragmentLinker *iface) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + ULONG refcount = InterlockedIncrement(&This->ref); + + TRACE("%p increasing refcount to %u.\n", This, refcount); + + return refcount; +} + +static ULONG WINAPI d3dx9_fragment_linker_Release(ID3DXFragmentLinker *iface) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + ULONG refcount = InterlockedDecrement(&This->ref); + + TRACE("%p decreasing refcount to %u.\n", This, refcount); + + if (!refcount) + { + IDirect3DDevice9_Release(This->device); + HeapFree(GetProcessHeap(), 0, This); + } + + return refcount; +} + +static HRESULT WINAPI d3dx9_fragment_linker_GetDevice(ID3DXFragmentLinker *iface, struct IDirect3DDevice9 **device) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + TRACE("iface %p, device %p\n", This, device); + + if (!device) + { + WARN("Invalid argument supplied.\n"); + return D3DERR_INVALIDCALL; + } + + IDirect3DDevice9_AddRef(This->device); + + *device = This->device; + + TRACE("Returning device %p\n", *device); + + return S_OK; +} + +static UINT WINAPI d3dx9_fragment_linker_GetNumberOfFragments(ID3DXFragmentLinker *iface) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(): stub\n", This);
return E_NOTIMPL; }
-HRESULT WINAPI D3DXCreateFragmentLinkerEx(IDirect3DDevice9 *device, UINT size, DWORD flags, ID3DXFragmentLinker **linker) +static D3DXHANDLE WINAPI d3dx9_fragment_linker_GetFragmentHandleByIndex(ID3DXFragmentLinker *iface, UINT index) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%u): stub\n", This, index); + + return NULL; +} + +static D3DXHANDLE WINAPI d3dx9_fragment_linker_GetFragmentHandleByName(ID3DXFragmentLinker *iface, const char *name) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%s): stub\n", This, debugstr_a(name)); + + return NULL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_GetFragmentDesc(ID3DXFragmentLinker *iface, D3DXHANDLE name, + D3DXFRAGMENT_DESC *frag_desc) { - FIXME("device %p, size %u, flags %#x, linker %p: stub.\n", device, size, flags, linker); + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface);
- if (linker) - *linker = NULL; + FIXME("(%p)->(%p, %p): stub\n", This, name, frag_desc);
return E_NOTIMPL; }
+static HRESULT WINAPI d3dx9_fragment_linker_AddFragments(ID3DXFragmentLinker *iface, const DWORD *fragments) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%p): stub\n", This, fragments); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_GetAllFragments(ID3DXFragmentLinker *iface, ID3DXBuffer **buffer) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%p): stub\n", This, buffer); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_GetFragment(ID3DXFragmentLinker *iface, D3DXHANDLE name, + ID3DXBuffer **buffer) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%p, %p): stub\n", This, name, buffer); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_LinkShader(ID3DXFragmentLinker *iface, const char *profile, + DWORD flags, const D3DXHANDLE *fragmenthandles, UINT fragments, ID3DXBuffer **buffer, + ID3DXBuffer **errors) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%s, 0x%x, %p, %u, %p, %p): stub\n", This, debugstr_a(profile), flags, fragmenthandles, + fragments, buffer, errors); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_LinkVertexShader(ID3DXFragmentLinker *iface, const char *profile, + DWORD flags, const D3DXHANDLE *fragmenthandles, UINT fragments, IDirect3DVertexShader9 **shader, + ID3DXBuffer **errors) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%s, 0x%x, %p, %u, %p, %p): stub\n", This, debugstr_a(profile), flags, fragmenthandles, + fragments, shader, errors); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_LinkPixelShader(ID3DXFragmentLinker *iface, const char *profile, + DWORD flags, const D3DXHANDLE *fragmenthandles, UINT fragments, IDirect3DPixelShader9 **shader, + ID3DXBuffer **errors) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(%s, 0x%x, %p, %u, %p, %p): stub\n", This, debugstr_a(profile), flags, fragmenthandles, + fragments, shader, errors); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3dx9_fragment_linker_ClearCache(ID3DXFragmentLinker *iface) +{ + struct d3dx9_fragment_linker *This = impl_from_ID3DXFragmentLinker(iface); + + FIXME("(%p)->(): stub\n", This); + + return E_NOTIMPL; +} + +static const struct ID3DXFragmentLinkerVtbl d3dx9_fragment_linker_vtbl = +{ + d3dx9_fragment_linker_QueryInterface, + d3dx9_fragment_linker_AddRef, + d3dx9_fragment_linker_Release, + d3dx9_fragment_linker_GetDevice, + d3dx9_fragment_linker_GetNumberOfFragments, + d3dx9_fragment_linker_GetFragmentHandleByIndex, + d3dx9_fragment_linker_GetFragmentHandleByName, + d3dx9_fragment_linker_GetFragmentDesc, + d3dx9_fragment_linker_AddFragments, + d3dx9_fragment_linker_GetAllFragments, + d3dx9_fragment_linker_GetFragment, + d3dx9_fragment_linker_LinkShader, + d3dx9_fragment_linker_LinkVertexShader, + d3dx9_fragment_linker_LinkPixelShader, + d3dx9_fragment_linker_ClearCache +}; + +HRESULT WINAPI D3DXCreateFragmentLinkerEx(IDirect3DDevice9 *device, UINT size, DWORD flags, ID3DXFragmentLinker **linker) +{ + struct d3dx9_fragment_linker *object; + + TRACE("device %p, size %u, flags %#x, linker %p.\n", device, size, flags, linker); + + object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->ID3DXFragmentLinker_iface.lpVtbl = &d3dx9_fragment_linker_vtbl; + object->ref = 1; + + IDirect3DDevice9_AddRef(device); + object->device = device; + object->flags = flags; + + *linker = &object->ID3DXFragmentLinker_iface; + + return S_OK; +} + +HRESULT WINAPI D3DXCreateFragmentLinker(IDirect3DDevice9 *device, UINT size, ID3DXFragmentLinker **linker) +{ + TRACE("device %p, size %u, linker %p.\n", device, size, linker); + + return D3DXCreateFragmentLinkerEx(device, size, 0, linker); +} + HRESULT WINAPI D3DXGetShaderSamplers(const DWORD *byte_code, const char **samplers, UINT *count) { UINT i, sampler_count = 0; diff --git a/dlls/d3dx9_36/tests/shader.c b/dlls/d3dx9_36/tests/shader.c index e6326bc411..acd361a01e 100644 --- a/dlls/d3dx9_36/tests/shader.c +++ b/dlls/d3dx9_36/tests/shader.c @@ -6575,6 +6575,54 @@ static void test_shader_semantics(void) } }
+static void test_fragment_linker(void) +{ + HWND wnd; + IDirect3D9 *d3d; + IDirect3DDevice9 *device; + D3DPRESENT_PARAMETERS d3dpp; + HRESULT hr; + ULONG count; + ID3DXFragmentLinker *linker; + + if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0, + 640, 480, NULL, NULL, NULL, NULL))) + { + skip("Couldn't create application window\n"); + return; + } + if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION))) + { + skip("Couldn't create IDirect3D9 object\n"); + DestroyWindow(wnd); + return; + } + + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device); + if (FAILED(hr)) + { + skip("Failed to create IDirect3DDevice9 object %#x\n", hr); + IDirect3D9_Release(d3d); + DestroyWindow(wnd); + return; + } + + hr = D3DXCreateFragmentLinker(device, 1024, &linker); + ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr); + linker->lpVtbl->Release(linker); + + count = IDirect3DDevice9_Release(device); + ok(count == 0, "The Direct3D device reference count was %u, should be 0\n", count); + + count = IDirect3D9_Release(d3d); + ok(count == 0, "The Direct3D object reference count was %u, should be 0\n", count); + + if (wnd) DestroyWindow(wnd); +} + START_TEST(shader) { test_get_shader_size(); @@ -6589,4 +6637,6 @@ START_TEST(shader) test_registerset(); test_registerset_defaults(); test_shader_semantics(); + test_fragment_linker(); + test_fragment_linker(); }
On Tue, Nov 26, 2019 at 4:06 AM Alistair Leslie-Hughes leslie_alistair@hotmail.com wrote:
@@ -6589,4 +6637,6 @@ START_TEST(shader) test_registerset(); test_registerset_defaults(); test_shader_semantics();
- test_fragment_linker();
- test_fragment_linker();
}
Why run it twice? Also you might want to check D3DXCreateFragmentLinkerEx() too and explicitly check that the returned interface is not NULL. In general, please use the current d3d style (period at the end of message strings, !count rather than count == 0, no calling the object "This", proper function TRACEs, ...). Also please use the heap allocation helpers.
Does the game mentioned in the referenced bug work with this?
Hi Matteo,
I'll fix up the patch as suggested.
No the game still doesn't run with this patch, however if AddFragments return S_OK, then it does run with graphical glitches as expected.
Alistair.
________________________________ From: Matteo Bruni matteo.mystral@gmail.com Sent: Wednesday, 27 November 2019 9:50 PM To: Alistair Leslie-Hughes leslie_alistair@hotmail.com Cc: wine-devel@winehq.org wine-devel@winehq.org Subject: Re: [PATCH] d3dx9: Implement D3DXCreateFragmentLinker/Ex
On Tue, Nov 26, 2019 at 4:06 AM Alistair Leslie-Hughes leslie_alistair@hotmail.com wrote:
@@ -6589,4 +6637,6 @@ START_TEST(shader) test_registerset(); test_registerset_defaults(); test_shader_semantics();
- test_fragment_linker();
- test_fragment_linker();
}
Why run it twice? Also you might want to check D3DXCreateFragmentLinkerEx() too and explicitly check that the returned interface is not NULL. In general, please use the current d3d style (period at the end of message strings, !count rather than count == 0, no calling the object "This", proper function TRACEs, ...). Also please use the heap allocation helpers.
Does the game mentioned in the referenced bug work with this?