iXit / wine-nine-standalone

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

Nine only works when installed to system32/syswow64 #151

Closed 9ary closed 1 year ago

9ary commented 1 year ago

For some reason I could only get nine to work properly when the DLL is installed to the windows system directories. Dropping the DLL next to an executable does not work. This means that if I want some programs to use wined3d and others to use nine, I have to enable nine globally and then link or copy wine's stock d3d9.dll in programs' directories which feels a bit backwards.

For context on why I need this: Fusion 360's AdCefWebBrowser (the data panel) only renders properly on wined3d, it's broken with both DXVK (black screen) and nine (glitchy rendering). However, the main application has rendering issues with wined3d which are fixed by DXVK (requires invasive and not completely functional child rendering patch) and nine (works great!).

(This is still broken after removing the dll override or setting it to builtin, see #150).

dungeon007 commented 1 year ago

"Dropping the DLL next to an executable does not work."

Well that works, but maybe other way around might be better for you. Let say without installation of gallium-nine-standalone. So, if you are more fine with copying and dropping things around... then you can just copy "d3d9-nine.dll.so" into a wine folder. I mean there where else wine libs are installed, usually /usr/lib/wine/ or whatever. And then just make a link to that named d3d9.dll. The link which you can put into a game folder, where you want nine to run. Only problem with this might be that if you have some else wrapper that would also like to be named exactly d3d9.dll :D

No, nine does not require neither to be installed in system32 nor in syswow64. Nor you need ninewinecfg at all (that is just for user friendliness reasons, for enable/disable/setting/checkings reasons) Neither you have to really touch registry at all. Neither you need to particulary set it to native, it is already set. Just drop it. ... But that only IF you are fine with copyng things around AND if you know that else parts required are correctly installed and in place OR if you are aware of at least one problem that this approach could make...

9ary commented 1 year ago

Sorry, I don't think you understood me.

Well that works, but maybe other way around might be better for you. Let say without installation of gallium-nine-standalone. So, if you are more fine with copying and droping things around... then you can just copy "d3d9-nine.dll.so" into a wine folder. I mean there where else wine libs are installed, usually /usr/lib/wine/ or whatever. And then just make a link to that named d3d9.dll. The link which you can put into a game folder, where you want nine to run. Only probelem with this might be that if you have some else wrapper that would also like to be named d3d9.dll :D

This does not work. According to debug logs, Wine apparently tries to load the d3d9.dll I'm putting there, but it is very clear that nine is not actually in use. The only way I've gotten it to work is by putting nine's d3d9.dll in system32/syswow64 in my wine prefix.

Neither you need to set it to native, it is already set. Just drop it.

ninewinecfg.exe erroneously sets a DLL override to native, not me. https://github.com/iXit/wine-nine-standalone/blob/631988f1c71c4973155976e520517d5018af4967/ninewinecfg/main.c#L366-L376 https://github.com/iXit/wine-nine-standalone/blob/9abd0b46df8e0f76981500757d717baf602e3112/common/registry.c#L13 To be clear, as stated in #150, d3d9-nine.dll is a fake DLL, so native is incorrect and will cause wine to skip it entirely. There is no reason to set it to builtin either because that's the default.

dungeon007 commented 1 year ago

Which WINE version and gallium-nine-standalone version? Yesterday was 0.9 forced to be released because of breakage in WINE 8.3, so i just wanna be sure, you are using correct things. Maybe it is just app specific issue, i guess you can post under var WINEDEBUG=+loaddll so that we could see what happens there.

9ary commented 1 year ago

Wine 8.2 and nine 0.8 from the Arch repos. I'll try the new releases soon but there are no significant changes in 0.9, just a few warning fixes. The compatibility issues are only relevant to the prebuilt binaries provided here as far as I can tell.

dungeon007 commented 1 year ago

Well, what i described up there works on Debian, maybe because wine and libs are at different places on Arch or something. Not sure who is using arch here to check this... @axeldavy i guess.

axeldavy commented 1 year ago

The way the dll is loading is a bit complicated. From what I understand, when you load a dll on windows, it loads first the dll in the current dir, then if it is not available, or if that dll tries to load again the dll (for example it is a wrapper), it loads the system one. But you cannot know if the dll in the game dir is a wrapper or not.

It is my understanding that setting to native a dll causes the windows full behaviour. native then wine causes the first dll to be loaded to be the native one (for example in the game dir) then the wine one.

Ofc if you want the d3d9-nine.dll to be used, you need to rename it d3d9.dll. But you also need to configure the native/system behaviour right.

9ary commented 1 year ago

The way the dll is loading is a bit complicated. From what I understand, when you load a dll on windows, it loads first the dll in the current dir, then if it is not available, or if that dll tries to load again the dll (for example it is a wrapper), it loads the system one.

The search order is described at https://wiki.winehq.org/Wine_User%27s_Guide#DLL_Overrides

DLLs usually get loaded in the following order:

  • The directory the program was started from.
  • The current directory.
  • The Windows system directory.
  • The Windows directory.
  • The PATH variable directories.

But you cannot know if the dll in the game dir is a wrapper or not.

This is specified in the PE metadata. See https://gitlab.winehq.org/wine/wine/-/blob/fbfa4a3aed432257931efb436b53fb891afc5fb5/dlls/ntdll/unix/loader.c?page=2#L1607-1612.

It is my understanding that setting to native a dll causes the windows full behaviour. native then wine causes the first dll to be loaded to be the native one (for example in the game dir) then the wine one.

As you can see in the source code linked above, setting the override to native simply causes wine to ignore fake DLLs.

Ofc if you want the d3d9-nine.dll to be used, you need to rename it d3d9.dll.

Yes of course, I am doing that.

Anyway again, copying/linking wine's stock d3d9.dll next to the executable works: with nine enabled globally, this is enough to get individual programs to use wined3d instead of nine. But doing the same thing with d3d9-nine.dll (renamed appropriately to d3d9.dll) doesn't work. The debug log shows that wine is trying to use that DLL, but I do not see the message that says nine is active, and I can clearly see the broken rendering caused by wined3d.

9ary commented 1 year ago

Okay, I think I've figured it out. ninewinecfg does not link the fake DLL, but the .dll.so. On top of that, it seems to be swapping the 32 and 64 bit versions around this turns out to be correct:

$ file .fusion360/drive_c/windows/system32/d3d9.dll 
.fusion360/drive_c/windows/system32/d3d9.dll: symbolic link to /usr/lib/wine/x86_64-unix/d3d9-nine.dll.so

$ file .fusion360/drive_c/windows/syswow64/d3d9.dll
.fusion360/drive_c/windows/syswow64/d3d9.dll: symbolic link to /usr/lib32/wine/i386-unix/d3d9-nine.dll.so

So my problem was that the fake DLL is in fact supposed to be a no-op. I don't think it really needs to be built, shipped or installed in this case since we already have Wine's built-in DLL and the fake DLL only causes confusion.

dhewg commented 1 year ago

A WINE installation consists of files in /usr/lib/wine, which in part get copied to each WINE prefix. The fake dlls are used to fully integrate nine into a WINE installation, meaning the dll.so and the fake dll get copied to /usr/lib/, and WINE itself then copies the fake dll to each prefix, just like it does for each of it's own libs.

So that's a different way to install it. Our nine-install.sh and winetricks approach is completely different, we don't even want to touch stuff in /usr/lib/wine, we only modify one prefix at a time.

So there is a reason for those fake dlls, or at least there used to be. The picture changed with the PE conversion. And the latest v0.9 release requires at least WINE v5.7. So we may indeed remove the fake dll stuff

9ary commented 1 year ago

My point is, the fake DLL isn't serving the purpose it's meant to currently. It made sense with DLL redirects, but it doesn't in the current state of things. Shipping a real PE library would change this, but that's a different issue.

dungeon007 commented 1 year ago

Since WINE 8.1 set Windows 10 by default for new prefixes, seems every release have some interesting bugs. Maybe we can employe some AI to auto fix bugs per everybody liking :D

dhewg commented 1 year ago

Where did the confusion with the fake DLLs come from?

If you would use the binary releases here or used winetricks you wouldn't even have or notice anything wrt fake DLLs. Does the arch package install them?

9ary commented 1 year ago

Where did the confusion with the fake DLLs come from?

If you would use the binary releases here or used winetricks you wouldn't even have or notice anything wrt fake DLLs. Does the arch package install them?

Yeah, Arch installs them to /usr/lib/wine/x86_64-windows and /usr/lib32/wine/i386-windows, which causes Wine to copy them to the prefix. I only realized afterwards that ninewinecfg links the .dll.so instead.

As far as I can tell, the binary releases in here never actually install the fake DLLs to the prefix, so it's not like they are being used for anything. Hence #152.

dhewg commented 1 year ago

Okay, that makes more sense now ;)

So all that sounds like the fake DLLs still work with recent WINE versions and you're actually using them because the arch package does the integration as I described above. Which means we shouldn't merge #152? Or do I miss another piece of the puzzle?

9ary commented 1 year ago

What happened is I was trying to copy/link the fake d3d9-nine.dll in my wine prefix to d3d9.dll in fusion 360's install directory. What I didn't realize is that the fake DLL actually forwards the lookup to the system .dll.so with the same name, rather than its internal name (if there is even such a thing, but I did see the name inside the file). So I ended up using wine's built-in d3d9 anyway.

That said, I've just tested, and either the fake DLL or the .dll.so (renamed to .dll) needs to be present in system32 for ninewinecfg to find anything. Which makes #152 bogus, so I will close it.

dhewg commented 1 year ago

Alright. I believe most of us are not testing the fake DLL integration approach at all, so it's definitely possible that there's room for improvement for that.

9ary commented 1 year ago

Other than #150 I don't think there's anything to be done from here, all the logic for this is in wine itself.