iXit / wine-nine-standalone

Build Gallium Nine support on top of an existing WINE installation
GNU Lesser General Public License v2.1
277 stars 23 forks source link

Setting a native DLL override for d3d9 is incorrect #150

Open 9ary opened 1 year ago

9ary commented 1 year ago

d3d9-nine.dll is a fake DLL, so setting a DLL override to native is incorrect. Installing it as d3d9.dll is sufficient, nine still works with the override removed.

To clarify: setting a DLL override to native means that wine should only load real DLLs, setting it to builtin means it should only load fake DLLs.

dhewg commented 1 year ago

It's only a fake DLL if installed in a certain way. Usually it is a unix library without the corresponding fake DLL.

The override is required on some WINE versions at least. When did that change? We cannot rip out code if that breaks using nine on older WINE versions.

9ary commented 1 year ago

I doubt Wine has ever considered the .dll.so to be a native DLL, and it definitely doesn't think the fake DLL is one. Since 5.7 is apparently the oldest supported version, it'd be good to check what happens there.

dhewg commented 1 year ago

"native override" doesn't necessarily mean there's a win32 native DLL.

The override is required so WINE picks up a d3d9.dll copy from a prefix at all. Without it it would always use the wined3d copy from the WINE installation.

But since your arch package does the nine<->wine integration that picture changes and the override apparently gets useless and redundant. AFAICT the override is still required without that integration, i.e. when using our binary releases with either nine-install.sh or winetricks.

9ary commented 1 year ago

I've packaged this project for NixOS as well (see #153), and I do not use the fake DLLs at all there. Nothing is installed to Wine's system path. Wine picks up d3d9.dll just fine with no override set at all.

I just did an experiment and the results are interesting. This is on Arch, Wine 8.3, nine 0.8. I've installed the (proper) d3d9.dll from nine into the Fusion 360 directory. AdCefWebBrowser.exe is in a subdirectory, so it never sees this DLL (I want it to use wined3d, due to rendering issues with nine).

So it seems that Wine will load nine regardless of the override setting unless it's disabled. This sounds like a wine bug, unix libraries should be treated as builtin DLLs.

Messing with overrides for d3d9-nine.dll (with the fake dll installed to the prefix's system32):

This is the correct behavior.

dhewg commented 1 year ago

I'd have to test it again to make sure, but that sounds like a change in WINE behaviour to me. Older WINE versions definitely need that override

9ary commented 1 year ago

I've managed to work around this by creating a DLL with no code, but all symbols forwarded to d3d9-nine. This DLL is recognized by wine as a native DLL, so I can drop it in system32, set a global override to builtin, and then an application-specific override for Fusion360.exe to native. The result is as expected: Fusion uses nine, and nothing else.

The downside is that I had to use mingw for this, it would be nice to figure out how to do this using winegcc instead, to avoid adding an extra build dependency.

d3d9.def (can be generated from the .spec with winebuild and then running a simple sed on the output):

LIBRARY d3d9.dll

EXPORTS
  Direct3DShaderValidatorCreate9=d3d9-nine.Direct3DShaderValidatorCreate9 @1
  PSGPError=d3d9-nine.PSGPError @2 PRIVATE
  PSGPSampleTexture=d3d9-nine.PSGPSampleTexture @3 PRIVATE
  D3DPERF_BeginEvent=d3d9-nine.D3DPERF_BeginEvent @4
  D3DPERF_EndEvent=d3d9-nine.D3DPERF_EndEvent @5
  D3DPERF_GetStatus=d3d9-nine.D3DPERF_GetStatus @6
  D3DPERF_QueryRepeatFrame=d3d9-nine.D3DPERF_QueryRepeatFrame @7
  D3DPERF_SetMarker=d3d9-nine.D3DPERF_SetMarker @8
  D3DPERF_SetOptions=d3d9-nine.D3DPERF_SetOptions @9
  D3DPERF_SetRegion=d3d9-nine.D3DPERF_SetRegion @10
  DebugSetLevel=d3d9-nine.DebugSetLevel @11 PRIVATE
  DebugSetMute=d3d9-nine.DebugSetMute @12
  Direct3DCreate9=d3d9-nine.Direct3DCreate9 @13
  Direct3DCreate9Ex=d3d9-nine.Direct3DCreate9Ex @14

Compile with x86_64-w64-mingw32-gcc d3d9.def -shared -o d3d9.dll.

Here's what happens if I try to use winegcc:

$ winegcc d3d9.def -shared -o d3d9.dll  -m64 -mwindows -L/nonexistant 
tmp64180562/d3d9-00000000.spec-00000000.s: Assembler messages:
tmp64180562/d3d9-00000000.spec-00000000.s:2: Error: can't resolve d3d9 - nine.Direct3DShaderValidatorCreate9
tmp64180562/d3d9-00000000.spec-00000000.s:3: Error: can't resolve d3d9 - nine.PSGPError
tmp64180562/d3d9-00000000.spec-00000000.s:4: Error: can't resolve d3d9 - nine.PSGPSampleTexture
tmp64180562/d3d9-00000000.spec-00000000.s:5: Error: can't resolve d3d9 - nine.D3DPERF_BeginEvent
tmp64180562/d3d9-00000000.spec-00000000.s:6: Error: can't resolve d3d9 - nine.D3DPERF_EndEvent
tmp64180562/d3d9-00000000.spec-00000000.s:7: Error: can't resolve d3d9 - nine.D3DPERF_GetStatus
tmp64180562/d3d9-00000000.spec-00000000.s:8: Error: can't resolve d3d9 - nine.D3DPERF_QueryRepeatFrame
tmp64180562/d3d9-00000000.spec-00000000.s:9: Error: can't resolve d3d9 - nine.D3DPERF_SetMarker
tmp64180562/d3d9-00000000.spec-00000000.s:10: Error: can't resolve d3d9 - nine.D3DPERF_SetOptions
tmp64180562/d3d9-00000000.spec-00000000.s:11: Error: can't resolve d3d9 - nine.D3DPERF_SetRegion
tmp64180562/d3d9-00000000.spec-00000000.s:12: Error: can't resolve d3d9 - nine.DebugSetLevel
tmp64180562/d3d9-00000000.spec-00000000.s:13: Error: can't resolve d3d9 - nine.DebugSetMute
tmp64180562/d3d9-00000000.spec-00000000.s:14: Error: can't resolve d3d9 - nine.Direct3DCreate9
tmp64180562/d3d9-00000000.spec-00000000.s:15: Error: can't resolve d3d9 - nine.Direct3DCreate9Ex
winebuild: /usr/bin/gcc failed with status 1
winegcc: /usr/bin/winebuild failed

Edit: I managed to make a DLL using winebuild, but for some reason it causes Fusion to be unresponsive for a while at startup before it becomes usable. This isn't a problem with the mingw DLL...