Open Bug 1849092 Opened 9 months ago Updated 2 months ago

Window is blurred when not maximized with widget.wayland.fractional-scale.enabled

Categories

(Core :: Widget: Gtk, defect, P3)

defect

Tracking

()

UNCONFIRMED

People

(Reporter: me, Unassigned)

References

(Blocks 2 open bugs)

Details

Steps to reproduce:

Set widget.wayland.fractional-scale.enabled = true, restart Firefox, don't maximize the window.

Running Nightly 2023-08-16 on Plasma 5.27.7. For some reason, maximized windows render correctly. Also, pressing "force device reset" in about:support makes the window not blurry (and slightly smaller, which to me sounds like there might be some rounding error somewhere?) until the next repaint.

Actual results:

The window is blurry.

Expected results:

The window is not blurry.

Flags: needinfo?(stransky)

The Bugbug bot thinks this bug should belong to the 'Core::Widget: Gtk' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Widget: Gtk
Product: Firefox → Core
Blocks: wayland
Flags: needinfo?(stransky)
Priority: -- → P3

Is that a recent regression?

Can you try to use mozregression to find a broken commit?
https://fedoraproject.org/wiki/How_to_debug_Firefox_problems#Use_Mozregression_tool
Thanks.

Flags: needinfo?(me)

It only happens with native fractional scaling enabled, which landed in yesterday's Nightly as far as I can tell? The default scaling setup isn't affected.

Flags: needinfo?(me)

My understanding of Firefox's implementation of Wayland is that the toplevel surface is created by Gtk3's window code - Gtk3 draws the window shadows, borders, and background - then Firefox itself renders in a subsurface which is positioned and sized to appear only within the "window area" (excluding shadows) - and for fractional scaling, wl_viewport is only used on the subsurface, not the toplevel?

If so, the cause of this issue is almost certainly due to rounding errors in position and size caused by the differences between the toplevel surface (presumably rendered by Gtk3 at nearest integer buffer scale then upscaled or downscaled to the fractional scale by the compositor) and the subsurface (intended to be rendered directly at fractional scale). The fractional-scale-v1 protocol is only designed to be used for toplevel surfaces: "For toplevel surfaces, the size is rounded halfway away from zero. The rounding algorithm for subsurface position and size is not defined." https://wayland.app/protocols/fractional-scale-v1

I think to fix this fully and completely, Firefox probably would have to handle its own toplevel surfaces rather than going through Gtk (which would also mean that Gtk can't be used for drawing shadows, window borders, etc - and it probably also means that Gtk can't be used for input handling). Some of the later comments on https://bugzilla.mozilla.org/show_bug.cgi?id=1701123 are relevant.

A possible "hack" to avoid the rounding problem might be to have Firefox's subsurface cover the exact same area as Gtk's toplevel surface - i.e. have the subsurface also cover the area where the shadow is rendered. But even if this work, it depends on non-specified behaviour. Also, Firefox's own drawing would have to be padded within the subsurface to only be within the "window area", which brings up new and different rounding error problems (the edges of the window area on Gtk's toplevel surface might not line up with physical pixels).

I should note that on my screen (3840x2160 at 175% in GNOME 44), this issue is also affecting maximized windows. Gtk still draws a border (actually a thin shadow) around the edges of maximized windows, so the rounding error issue happens there too. Fullscreen windows also seem to be affected on my system but I don't have an explanation for why that is happening.

With GNOME 45 I get the reported behavior - blurry rendering unless the window is maximized.

It seems like GNOME 44's implementation of fractional-scale-v1 wasn't complete (see https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2726). I couldn't get any compatible programs to render without blurring.

I'm repeating myself a bit here, but I just want to make it clear - as of GNOME 45, the implementation of the fractional-scale-v1 extension is correct and complete to the best of my knowledge. (GNOME 44 did have a bug in its implementation that affected Chromium, which has since been fixed.) The blurriness of Firefox specifically is caused by a combination of two problems.

  1. The specification of the fractional-scale-v1 extension itself is incomplete, and does not define handling for subsurfaces:

    For toplevel surfaces, the size is rounded halfway away from zero. The rounding algorithm for subsurface position and size is not defined.

    The alternate fractional scaling proposal (now called fractional-scale-v2) did define handling for subsurfaces, but was more involved for compositors to handle due to multiple coordinate systems. It has no implementations, and is currently stalled.

  2. Due to the unfortunate design choice of using Gtk to create "toplevel" windows despite Firefox not actually using Gtk as a GUI toolkit, combined with the fact that Gtk itself does not itself support fractional scaling, and Gtk3 doesn't provide a good/performant way for Firefox to render its own content into the toplevel surface, Firefox currently does all of its own drawing in a positioned and sized subsurface.

As far as I can see, there's one solution and one workaround:

Solution: Stop using Gtk, and have Firefox on Wayland speak wayland protocols itself directly. Firefox is already doing a bunch of wayland stuff directly anyways to bypass Gtk via the subsurface. This would also fix the lag between resizing a window and the Firefox subsurface getting updated - and would give Firefox direct access to input events, fixing existing issues resulting from getting input events after Gtk processes them.

Workaround: You might get lucky, and find out that in existing compositors, having a subsurface positioned at 0,0 and with size the same as the toplevel window (according to the fractional-scale-v1 specified toplevel rounding) happens to align it correctly. This requires that Firefox pad its subsurface with transparency over the areas where Gtk is drawing the window shadows and borders. There is of course a rounding problem here, since the Gtk toplevel surface is not fractionally scaled, so the borders/shadows that it draws will not lineup with physical pixels.

(In reply to Calvin Walton from comment #6)

Solution: Stop using Gtk, and have Firefox on Wayland speak wayland protocols itself directly. Firefox is already doing a bunch of wayland stuff directly anyways to bypass Gtk via the subsurface. This would also fix the lag between resizing a window and the Firefox subsurface getting updated - and would give Firefox direct access to input events, fixing existing issues resulting from getting input events after Gtk processes them.

Amount of such work would be enormous. But well, we can look that way of course.

You need to log in before you can comment on or make changes to this bug.