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

Graphic issues on certain GPUs #2

Open
Eroica opened this issue Sep 28, 2022 · 13 comments
Open

Graphic issues on certain GPUs #2

Eroica opened this issue Sep 28, 2022 · 13 comments

Comments

@Eroica
Copy link

Eroica commented Sep 28, 2022

Hi there,

I was hoping that you might help investigating an issue with the Mica effect that I noticed on certain hardware. Similar to you, I was applying Windows 11's Mica style to a JavaFX window by setting the necessary "magic" values (20 and 1029 before 22H2, now 38 on 22H2). While this works great on my main development machine, there seems to be a graphical glitch on certain hardware that make the effect look wrong. For example, with your test code:

1

Left is how it should look, and right is how it actually looks on another computer that uses an NVIDIA GPU. My main computer where everything works as intended uses an AMD graphics card. The scene is set to Color.TRANSPARENT, so it seems the "real" color of the window shines through and is black.

At first I noticed this problem on a notebook that uses Intel integrated graphics. I put this on hold because I thought the 22H2 update might fix this issue. However, I now have 22H2 on both an AMD and an NVIDIA system, and the NVIDIA computer still has the same issue no matter if I use my original code or your library.

Now the interesting thing is that if I turn off hardware acceleration (System.setProperty("prism.order, "sw")), then both the NVIDIA and the Intel machine show the Mica effect correctly. The fact that other Windows applications (e.g. Explorer) also correctly show the Mica effect makes me think it might something internal to JavaFX---however, it seems, only on certain hardware. Would you happen to know what might be the cause of this?

I investigated a little bit more and I was able to achieve something by using Windows' SetLayeredWindowAttributes(hWnd, RGB(255, 0, 255), 0, LWA_COLORKEY); and setting the scene background to Magenta (here showcased with my program):

2

Again, left is how it should look, and right is how it looks on an NVIDIA system. What happens is that while the window correctly shows the Mica effect, it is completely mouse transparent, and only the magenta color is actually clickable (and of course there is this strange color fringe).

What I also found out is that other GUI toolkits are able to correctly "Mica-ify" a window on my NVIDIA system, e.g.:

https://github.com/martinet101/win32mica/
https://github.com/dongle-the-gadget/SystemBackdropTypes

However, they seem to do a little bit more than only setting DwmSetWindowAttribute. For example, the WPF example works with a CompositionTarget and a transparent color here: https://github.com/dongle-the-gadget/SystemBackdropTypes/blob/ab18f1aa70f0575e5df42ebad5ae2699b2ee4c9a/SystemBackdropTypes/MainWindow.xaml.cs#L34

Sadly, my knowledge about the Windows API is limited, so I wonder if you have any more insights on why this seems to be a JavaFX problem, and what exactly the drivers do different so that it only occurs on certain hardware.

@mimoguz
Copy link
Owner

mimoguz commented Sep 29, 2022

I don't think I can help. Looking at your comment, you seem more versed in Win32 API than me :)

I can add a few more points to your findings though. On my notebook, which has an NVidia card:

  • Replacing root.setStyle("-fx-background-color: transparent"); with root.getStylesheets().add(".root { -fx-background-color: transparent; }"); and removing scene.setFill(Color.TRANSPARENT); works, until I move the window to an external display.
  • The maximize button hover overlay problem I've mentioned in README is not there anymore, so clearly something's changed.

At this point, I don't think it is possible to create a mica window without doing it properly on stage creation. Probably a custom stage implementation is required here, but this is too big a task for what I use JavaFX for.

Sorry :(

@Eroica
Copy link
Author

Eroica commented Sep 29, 2022

No problem, thanks for your hint about the background color! Unfortunately, it doesn't seem to do the same on my NVIDIA desktop, so there might be even more uncertainties.

I also heard conflicting opinions on whether one has to use WS_EX_NOREDIRECTIONBITMAP at creation time or whether one can set it later with SetWindowLong. There are also some differences when using StageStyle.UNIFIED or not, but so far I wasn't able to find out what exactly JavaFX does different in these 2 cases when creating windows (https://github.com/openjdk/jfx/blob/86b854dc367fb32743810716da5583f7d59208f8/modules/javafx.graphics/src/main/native-glass/win/BaseWnd.cpp#L112).

I'll keep investigating this issue, if you have the time feel free to let me know about any changes that you noticed!

@Eroica Eroica closed this as completed Sep 29, 2022
@Eroica
Copy link
Author

Eroica commented Sep 29, 2022

An additional thing that I found out: If I use StageStyle.TRANSPARENT then Mica seems to work as expected! But of course, the window decorations are now missing. JavaFX skips some steps when the window is set to be transparent, or there is something going on with blending the effect onto the window: https://github.com/openjdk/jfx/blob/303bcdb9ba40b7d82e555d675dad8d028e018c86/modules/javafx.graphics/src/main/native-glass/win/GlassWindow.cpp#L807

@mimoguz
Copy link
Owner

mimoguz commented Sep 29, 2022

The most annoying part is that it just works on my desktop, which has an AMD card:

tabbed

:(

@Eroica
Copy link
Author

Eroica commented Oct 4, 2022

Hi,

using an undocumented -Dprism.forceUploadingPainter=true/System.setProperty("prism.forceUploadingPainter", "true"), I was able to make Mica work on my NVIDIA machine! Can you try it on your system? I will also check whether it works on my Intel graphics system later.

  • Use StageStyle.UNIFIED
  • scene.fill = Color.TRANSPARENT
  • Use a transparent background for the root node

By the way,

The most annoying part is that it just works on my desktop, which has an AMD card:

I had a similar experience. My main machine also uses AMD so in the beginning I thought that Mica works without problems. However, I had another user running AMD where for some reason, the same code didn't work! I needed to investigate that too. But if that forceUploadingPainter works on NVIDIA and Intel, I hope that it might also remove any inconsistencies on AMD hardware as well.

@mimoguz
Copy link
Owner

mimoguz commented Oct 4, 2022

It doesn't work on mine :( But maybe I'm doing it wrong? I'm more of a sbt person than maven person. How did you pass that option? I tried setting $env:MAVEN_OPTS/$env:JAVA_OPTS, and calling setProperty in main before launch().

@Eroica
Copy link
Author

Eroica commented Oct 4, 2022

I'm actually mainly using Gradle, with Gradle it depends a little bit on whether it runs a main() function or directly instantiates the JavaFX application.

In general, you could look for the way how to pass "JVM arguments" to Java. For example, in Gradle one can use applicationDefaultJvmArgs, and then you also need to prepend the option with a D like this: -Dprism.forceUploadingPainter=true

But it actually should work if you use System.setProperty before launch ... can you check whether other setProperty works, e.g. System.setProperty("prism.verbose", "true")? It should then print some information about your graphics configuration.

@mimoguz
Copy link
Owner

mimoguz commented Oct 4, 2022

Turns out you can list JVM options under JavaFX plugin configuration. And it works! Well, the title text background is still opaque but it works :)

@Eroica
Copy link
Author

Eroica commented Oct 4, 2022

Great to hear! I actually do not have this opaque title problem anymore, at least on my current 22H2 machine. I remember having it in the past (before 22H2), but I also put it off until later. Luckily, it seems to be gone for me, but I will look for a fix and tell you if it happens to me again.

For the sake of completeness, I'll collect my data points on Mica issues here:

Graphics Works out-of-the-box Works with forceUploadingPainter
AMD (Polaris, Navi) YES YES(1)
NVIDIA (30XX series) NO YES(2)
Intel (Xe) NO YES(2)

(1) With performance loss on monitors >60Hz.
(2) Possibly with performance loss on monitors >60Hz.

If I notice that it is driver-dependend, I'll lookup the versions and add them later.

@mimoguz
Copy link
Owner

mimoguz commented Oct 4, 2022

You can put 'yes' to both column for RX 570X. And yes, opaque background isn't an issue in 22H2, my notebook is not yet updated.

@Eroica
Copy link
Author

Eroica commented Oct 6, 2022

It turns out the Mica issue that the RX 580 user had was actually me additionally using DwmExtendFrameIntoClientArea (and me only applying Mica's light theme on a dark-themed desktop). So it seems AMD isn't affected by this in general.

One could now simply enable forceUploadingPainter on all systems, but I noticed a great performance loss if enabling that and also having a monitor with >60Hz. This might affect only AMD or could depend on the higher refresh rate in general.

In that case, also setting javafx.animation.fullspeed=true gets rid of what seems to be a frame limit.

Here is also some additional information on what forceUploadingPainter does:

... Note that it's only required for UploadingPainer. The PresentingPainter does not call uploadPixels(), and thus doesn't depend on RT-24168.

https://bugs.openjdk.org/browse/JDK-8091385

 * UploadingPainter is used when we need to render into an offscreen buffer.
 * The PresentingPainter is used when we are rendering to the main screen.
 */

https://github.com/openjdk/jfx/blob/master/modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/UploadingPainter.java

 * The PresentingPainter is used when we are rendering to the main screen.
 * UploadingPainter is used when we need to render into an offscreen buffer.
 */

https://github.com/openjdk/jfx/blob/master/modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/PresentingPainter.java

For now I'll update the table to be more general because in the end it only seems to depend on using AMD or not. I will probably build a check for a user's GPU and enable forceUploadingPainter if necessary, but if I find out another fix I will let you know!

@mimoguz
Copy link
Owner

mimoguz commented Oct 6, 2022

👍

You're awesome.

I will re-open this issue if you don't mind, just to make it a bit more visible. Who knows, maybe there is a third person on the internet that cares about JavaFX on Windows 11 🙂.

@mimoguz mimoguz reopened this Oct 6, 2022
Eroica added a commit to Eroica/Paletti that referenced this issue Oct 25, 2022
@ghost
Copy link

ghost commented Nov 27, 2023

👍

You're awesome.

I will re-open this issue if you don't mind, just to make it a bit more visible. Who knows, maybe there is a third person on the internet that cares about JavaFX on Windows 11 🙂.

me! 😃

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

No branches or pull requests

2 participants