Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VSTs not scaled properly on HiDPI displays #7683

Open
tresf opened this issue Feb 3, 2025 · 31 comments
Open

VSTs not scaled properly on HiDPI displays #7683

tresf opened this issue Feb 3, 2025 · 31 comments

Comments

@tresf
Copy link
Member

tresf commented Feb 3, 2025

When running Windows VSTs (either natively on Windows or via wine), they do not scale properly when run on HiDPI (e.g. 200%) displays.

Platform Scaling is honored by VST
Windows 11 (mingw) ✅ PASS
Windows 11 (msvc) 🚫 FAIL
Ubuntu 24.04 🚫 FAIL
  • Windows (mingw):
    Image

  • Windows (msvc):
    Image

  • Ubuntu 24.04 (AppImage)
    Image

Previously reported here: #4411

@tresf
Copy link
Member Author

tresf commented Feb 3, 2025

@tresf
Copy link
Member Author

tresf commented Feb 11, 2025

Workaround using X11:

  • Change plugin embedding to "none" inside LMMS (you can leave LMMS open)
  • Use winecfg to set the DPI (e.g. 192)
  • From a terminal, run:
    wineboot -k

Workaround using Wayland (taken from winehq's forums: https://forum.winehq.org/viewtopic.php?t=38372)

  • Change plugin embedding to "none" inside LMMS (you can leave LMMS open)
  • Extract the appimage (e.g. --appimage-extract)
  • Force wine to use wayland by adding the following lines to usr/lib/32/RemoveVstPlugin32 and /usr/lib/RemoveVstPlugin64 (from within squashfs-root).
      #!/bin/sh
    + export DISPLAY=
      appname="RemoteVstPlugin32.exe.so"
  • Run the AppRun file.
Image

@SpomJ
Copy link
Contributor

SpomJ commented Feb 11, 2025

I can't help but wonder why doesn't wine pull dpi automagically under X11. If it's a lack of standard, we could end up making a custom wine prefix and just automating the workaround since I don't see any other sensible way to resolve this.

A more interesting question though is windows-msvc. I'm genuinely confused here.

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

I can't help but wonder why doesn't wine pull dpi automagically under X11. If it's a lack of standard, we could end up making a custom wine prefix and just automating the workaround since I don't see any other sensible way to resolve this.

Yeah my thought is to add a button next to Vestige's wrench that sets the wine dpi and calls wineboot. It won't work in mixed dpi setups and will need a way to toggle back off, but would save a lot of headache.

On the other hand if Wayland is better at scaling maybe it's less of an issue and we just need to focus on Wayland. Although gnome doesn't play well with the Wayland version so IDK.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 12, 2025

Yeah my thought is to add a button next to Vestige's wrench that sets the wine dpi and calls wineboot. It won't work in mixed dpi setups and will need a way to toggle back off, but would save a lot of headache.

Honestly my guess is even simpler. QT already tells us DPI scaling, so we could just hardcode running wineboot at startup if using X11. Especially since the original issue is about decorations not matching the window dimensions. Though this probably needs to be toggleable.

Regarding wayland, I don't use gnome so I'm not aware of any issues with it specifically; but what I am using is a random ahh compositor called hyprland which so far didn't have any issues besides the discussed drag & drop problem. However I don't think we should be abandoning x11 support yet.

A solution for wayland embedding is also imminent and we're not getting away with something as easy as XEmbed this time We probably just want to use the Qt solution once it's done

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

we could end up making a custom wine prefix and just automating the workaround since I don't see any other sensible way to resolve this.

Honestly my guess is even simpler. QT already tells us DPI scaling, so we could just hardcode running wineboot at startup if using X11. Especially since the original issue is about decorations not matching the window dimensions. Though this probably needs to be toggleable.

I already thought about this and I'm sorry I did't comment on it specifically... IIRC, custom prefixes use custom install locations, won't this hide all the VSTs?

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

Regarding wayland, I don't use gnome so I'm not aware of any issues with it specifically;

Although I don't particularly care for it personally, it's the most common default desktop config for end-users, so it's tremendously important that we keep this in mind when adding feature or workarounds. AFAIR, there's a qt shim on startup that disables Wayland back-end in Qt because it's tremendously buggy on Gnome.

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

hardcode running wineboot at startup if using X11

Wouldn't this close any running Windows applications? This just seems dangerous.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 12, 2025

I already thought about this and I'm sorry I did[n]'t comment on it specifically... IIRC, custom prefixes use custom install locations, won't this hide all the VSTs?

AFAIK we don't actually install anything into prefixes so this would just isolate our wine settings & drive from generic user wine

hardcode running wineboot at startup if using X11

Wouldn't this close any running Windows applications? This just seems dangerous.

Probably want to test this, but I'm fairly certain wineboot wouldn't close different wine if they use separate prefixes.

Although I don't particularly care for it personally, it's the most common default desktop config for end-users, so it's tremendously important that we keep this in mind when adding feature or workarounds.

This is probably spinning into off-topic territory but honestly I would just add a check for gnome :P

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

AFAIK we don't actually install anything into prefixes so this would just isolate our wine settings & drive from generic user wine

VSTs install to the default prefix, so by leveraging our own, it breaks user space... unless I'm misunderstanding how prefixes work.

Probably want to test this, but I'm fairly certain wineboot wouldn't close different wine if they use separate prefixes.

Agreed, please see previous comment although they're not mutually exclusive. If the prefix is being used for other things (e.g. two copies of LMMS at once), it'll still break stuff if we do it blindly on startup.

This is probably spinning into off-topic territory but honestly I would just add a check for gnome

Sorry, this message may have been placed without proper context, qt is going to use x11 on gnome, it will do that automatically as can be observed by the launcher. I'm not exactly sure where this logic lies, but we need to keep this in mind as we develop a feature that makes any wayland or x11 asumptions.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 12, 2025

VSTs install to the default prefix, so by leveraging our own, it breaks user space... unless I'm misunderstanding how prefixes work.

I see what you mean now. Most VSTs I used are fairly old and thus usually just provide a dll without an installer. Still though, we could ask to install VSTs through LMMS, ask user to run wine with custom prefix or even just use files from default prefix since the only thing we care about is settings.

If the prefix is being used for other things (e.g. two copies of LMMS at once), it'll still break stuff if we do it blindly on startup.

Well for one we should probably kindly ask user not to launch two instances of lmms, and second, wineboot itself might not even be necessary. What I mean is by the time LMMS is launched if nothing uses the prefix wine server for it should be dead (if we ignore potential leaks which still exist) and thus launch with correct dpi, although this topic continues to drift from knowledge to speculation for me.

qt is going to use x11 on gnome

I see, so it's literally qt devs who implemented The Gnome Check (TM). That's funny.

we need to keep this in mind as we develop a feature that makes any wayland or x11 asumptions.

Again, QT does most of the heavy lifting with its abstractions hence me recommending to wait for QT embedding solution since otherwise the easiest method would literally be to ship a minimal compositor. And yet again, there are many reasons to not ditch x11 for a while still.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 12, 2025

So the solutions I'm aware of:

  • Ask wine for wayland if we run wayland (this still doesn't solve the problem with x11 or win-msvc and prevents embedding until qt does their job)
  • Ask wine to change DPI when we want to (this seems the most sensible thing to do as of now, however it mutates wine settings hence we need a custom prefix)
  • Don't ask wine and size down our embeds instead. (this is just treating the symptom, not the cause.)

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

I see what you mean now. Most VSTs I used are fairly old and thus usually just provide a dll without an installer.

Yeah, same, but I strongly feel that this represents the minority of how people use VSTs on Windows and this "majority" becomes more important once we mess with Wine prefix because they won't know the procedure for installing things that are new. Note that this also does not solve the problem of alienating previously installed VSTs, which we really don't want to do.

Still though, we could ask to install VSTs through LMMS, ask user to run wine with custom prefix or even just use files from default prefix since the only thing we care about is settings.

I'm not sure what this would look like to an end-user. I don't love the idea from a high-level, but I'm receptive to a creative idea that makes this seamless. If it requires a terminal, it's not a good end-user experience.

Again, QT does most of the heavy lifting with its abstractions hence me recommending to wait for QT embedding solution since otherwise the easiest method would literally be to ship a minimal compositor. And yet again, there are many reasons to not ditch x11 for a while still.

  • I think we ultimately need to disable embedding as our first step, it's just too problematic. This will start to draw parity between x11 and wayland.

  • The dpi stuff I believe belongs in the Vestige window but ONLY when we know we're running LMMS through the x11 mode. We can raise a TextFloat if it's a configuration we think is wrong. Having a way to detect and automatically fixing a system is better than making arbitrary assumptions about how they have wine configured. I'm just not comfortable with messing with someone's wine and I'm not comfortable with making our own. I think the best solution is to provide a helper.

WTR Qt abstractions: I'm not holding my breath for anything Qt related. We should be able to ship 1.3 with a good default VST experience.

@tresf
Copy link
Member Author

tresf commented Feb 12, 2025

So the solutions I'm aware of:

  • Ask wine for wayland if we run wayland (this still doesn't solve the problem with x11 or win-msvc and prevents embedding until qt does their job)
  • Ask wine to change DPI when we want to (this seems the most sensible thing to do as of now, however it mutates wine settings hence we need a custom prefix)
  • Don't ask wine and size down our embeds instead. (this is just treating the symptom, not the cause.)

Yeah this summarizes it perfectly. I just don't think a custom prefix is needed and we can add a helper in the UI to do the same to the default prefix, but only when the user explicitly decides to.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

I just don't think a custom prefix is needed and we can add a helper in the UI to do the same to the default prefix, but only when the user explicitly decides to.

That still leaves the issue of embed decorations differing from embed itself. Of course, we could just undo the QT scaling and then pull scaling from wine for consistency but yet again, that's kinda questionable

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

That still leaves the issue of embed decorations differing from embed itself.

Right, which is why embed probably needs to be disabled by default, but if you're instinct is to patch as part of this, I'm not opposed!

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

So regarding actual implementation, we can do this automatically with shell: wine reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v LogPixels /t REG_DWORD /d ${NEWDPI} /f, where $NEWDPI is 96*(scale we want).

In C++ this should take up roughly this form (shamelessly stolen from this SO post and edited for our need, I didn't actually test this):

HKEY hKey;
DWORD dpi = 96;

//open the registry with key_write access
int res = RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Desktop", 0, KEY_WRITE, &hKey);
if (ERROR_SUCCESS == res)
{
    if (RegSetValueExW(hKey, _T("LogPixels"), 0, REG_DWORD, (LPBYTE)&dpi, sizeof(DWORD)))
    {
        // Insert error handling here
    }
    RegCloseKey(hKey);
}
else {
    // Insert error handling here
}

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

So regarding actual implementation, we can do this automatically with shell:

In C++ this should take up roughly this form

Yeah the hard part is going to be deciding when and how. The C++ would be interesting to place in the codebase, but would have to be compiled by winegcc and then we'd have to decide how to execute it, so that's probably a non-starter. For this reason, it'll probably be easier to leverage the reg calls directly, but we'll want to read them in first so that we can pop-up a message in TextFloat or whatever. I think we have room in the ui next to the the wrench icon, or we could add something to the setting screen.

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

Another advantage of reading the value in is we can use it to fix the window embed size. Moving pieces (such as x11/Wayland) make this tricky too.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

The C++ would be interesting to place in the codebase, but would have to be compiled by winegcc and then we'd have to decide how to execute it

I'm not sure I get what you mean. RemoteVst already uses a bunch of Windows-specific functions, we could just add the function there and call it from wherever we want. This shouldn't be much of a problem and ideally we'd be doing this before any VST is loaded regardless.

Another advantage of reading the value in is we can use it to fix the window embed size.

Yes, although I'm a bit anticipating this since we'd need to undo Qt scaling first which isn't that hard but is a bit ugly.

Moving pieces (such as x11/Wayland) make this tricky too.

Yeah so as far as I'm aware, Wayland wine just doesn't care about registry value at all, so we'll need to if all of the changes to X11.

I think we have room in the ui next to the the wrench icon, or we could add something to the setting screen.

Settings is probably a better fit for this, mostly because scaling is universal and settings already tell you to restart everything if you aren't sure.

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

The C++ would be interesting to place in the codebase, but would have to be compiled by winegcc and then we'd have to decide how to execute it

I'm not sure I get what you mean. RemoteVst already uses a bunch of Windows-specific functions, we could just add the function there and call it from wherever we want.

Like more comms to RemoteVstPlugin? Or a new process? Or a Windows CLI tool? And why? If you think you can pull this off simpler and cleaner than just running a few CLI commands from Linux, knock yourself out!

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

So the way I imagine this working is we make a setting which is like a drop-down or something with options "none" (don't edit the value), "automatic" (calculate dpi with 96*) and values.

If current display is X11, we adjust decorations size according to dpi (if we get desperate we could just pull from settings, otherwise we either ask Vestige or use wine directly).

If current display is X11, upon init of the first VST, RemoteVst asks regedit to change settings the way I described above and then proceeds to work as normal

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

Like more comms to RemoteVstPlugin? Or a new process? Or a Windows CLI tool? And why? If you think you can pull this off simpler and cleaner than just running a few CLI commands from Linux, knock yourself out!

We probably want an in-house solution rather than asking the user to "btw run this in your terminal", and I'm a little bit skeptical towards the idea of running shell commands if we don't have to.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

The C++ method is more verbose - yes, but if you read into it, it literally does the same thing, just with C++ verbosity, so I still don't get your point. Though I have no experience with neither IPC nor winegcc

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

I like the workflow you're describing, but I still like the idea of interrogating this value if we want to display a warning in TextFloat.

"btw run this in your terminal"

I've strictly advocated against this nonsense lol.

skeptical towards the idea of running shell commands if we don't have to.

Regardless, it still benefits from being an explicit action (vs something that gets set the next time a plugin loads).

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

Also one thing I noticed about windows screenshots.

MinGW doesn't seem to even tell anything to Qt about Dpi and instead just bitmap upscales literally everything afterwards, hence the issue appears fixed. You can tell this by the fact sub-pixel font aliasing now spans multiple pixels even inside LMMS itself.

MSVC on the other hand does actually scale Qt interface meaning VSTs not being scaled are now apparent. I'm not sure about how to deal with this, and the only thing that comes to mind is doing something with scaling policies I tried before yet again.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

skeptical towards the idea of running shell commands if we don't have to.

Regardless, it still benefits from being an explicit action (vs something that gets set the next time a plugin loads).

Yes, but it introduces several questionable behaviors. If what you said before is true, we'd now need to kill all of the VSTs and then load them back, which both introduces more complexity and has drawbacks of non-VST apps that just happen to run through wine.

It's also pretty much reloading anyways, but partially.

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

The C++ method is more verbose - yes, but if you read into it, it literally does the same thing, just with C++ verbosity, so I still don't get your point.

I'm not sure where these verbosity sentiments come from... I've written registry settings in more languages than I care to admit, it's never been about the language verbosity, it's a matter of how it's presented to the user and when its presented to the user. If you want to write this up in Windows C++ I won't fight it.

Though I have no experience with neither IPC nor winegcc

Yet you're advocating for it, so I'll kindly invite you to try it and report back. I'm not attached to a particular solution.

@tresf
Copy link
Member Author

tresf commented Feb 13, 2025

Yes, but it introduces several questionable behaviors. If what you said before is true, we'd now need to kill all of the VSTs and then load them back, which both introduces more complexity and has drawbacks of non-VST apps that just happen to run through wine.

I feel like fixing the embed size alone makes a shell command to wine a necessity, but if you know of a way to correct this in the plugin that might be the place to do it.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

I feel like fixing the embed size alone makes a shell command to wine a necessity, but if you know of a way to correct this in the plugin that might be the place to do it.

My best guess is report window width and height as on-screen pixels (as opposed to virtual, scalable pixels), and then undo the scaling Qt does specifically for the frame.

This does mean we end up with a chain like this:

  1. VST reports height as 400px virtual
  2. RemoteVst reports height as 800px physical to LMMS (applying example 2x scaling set in wine)
  3. Divide reported height by 1.5x (assuming QT scaling is 1.5x) inside main app to get 534px virtual, which is transformed to 800px physical yet again by Qt.

However what would end up happening on matching scales is literally 400px (vst) -> 800px (reported) -> 400px (qt) -> 800px (display) which is unnecessary complexity.

@SpomJ
Copy link
Contributor

SpomJ commented Feb 13, 2025

Alternatively, we could make RemoteVst report sizes already accounting for general X11 scaling too, but I'm afraid it adds confusion either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants