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

Refactor draw code to use cairo_surface_set_device_scale #1337

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

bynect
Copy link
Member

@bynect bynect commented Apr 16, 2024

This fixes something that has been bugging me for a while.
Basically now dunst is scaling itself when drawing every single shape and text (with cairo and pango).
With this patch we render everything at a uniform scaling factor of 1 and scale everything afterwards using cairo_surface_set_device_scale.

This should have some advantages (apart from conciseness), like making scaling on wayland possible (like I discussed with @alebastr under #1316)

NOTE: Everything works on Xorg, however I can't test it on Wayland and my display is not Hi-Dpi, so I am not sure if the pango dpi scaling is being applied correctly. If someone can test it it would be great 👍🏻

@bynect
Copy link
Member Author

bynect commented Apr 16, 2024

I think that all the get_icon_width and get_*scale*icon function aren't needed anymore

@bynect bynect requested review from fwsmit and zappolowski April 16, 2024 20:09
@bynect
Copy link
Member Author

bynect commented Apr 16, 2024

I have no clue about why the test are failing 😢

@bynect
Copy link
Member Author

bynect commented Apr 19, 2024

I am trying to debug the use of uninitialized variables but even with libAsan I can't find it

@@ -100,7 +103,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t button_state) {
struct dunst_seat *seat = data;

input_handle_click(button, button_state, seat->pointer.x, seat->pointer.y);
double scale = wl_get_scale();
input_handle_click(button, button_state, seat->pointer.x/scale, seat->pointer.y/scale);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before wayland didn't scale the user input

@bynect
Copy link
Member Author

bynect commented Apr 19, 2024

Finally figured it out. Basically I forgot that the test didn't call draw_setup. Since I moved the initialization of the PangoContext in draw_setup it was undefined and thus buggy, but only in tests.

@codecov-commenter
Copy link

codecov-commenter commented Apr 19, 2024

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 57.14286% with 48 lines in your changes missing coverage. Please review.

Project coverage is 64.93%. Comparing base (e1e772c) to head (7edbebd).

Files with missing lines Patch % Lines
src/draw.c 59.61% 21 Missing ⚠️
src/wayland/wl.c 0.00% 14 Missing ⚠️
src/wayland/wl_seat.c 0.00% 4 Missing ⚠️
src/x11/x.c 0.00% 4 Missing ⚠️
test/draw.c 82.35% 3 Missing ⚠️
src/utils.c 0.00% 2 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1337      +/-   ##
==========================================
- Coverage   65.12%   64.93%   -0.20%     
==========================================
  Files          50       50              
  Lines        8654     8658       +4     
  Branches     1023     1023              
==========================================
- Hits         5636     5622      -14     
- Misses       3018     3036      +18     
Flag Coverage Δ
unittests 64.93% <57.14%> (-0.20%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@bynect
Copy link
Member Author

bynect commented Apr 19, 2024

Everything things to work. I think it is ready for merge.

Things we may want to consider

  • remove the icon scaling code (since we don't use it anymore). Alternatively we can render icons separately over the cairo surface to not downscale->upscale them. But this can be done in another pr.
  • integrate the new scaling method with wayland for per-monitor-dpi

@bynect
Copy link
Member Author

bynect commented May 1, 2024

@alebastr Where do you think should we place scale code so that the wayland backend can correctly get the scale needed? (to solve #1316)

Note that the pr is still not quite ready

@bynect bynect marked this pull request as draft July 2, 2024 07:30
@matejdro
Copy link
Contributor

matejdro commented Jul 3, 2024

If someone can test it it would be great 👍🏻

I can test it on Wayland if desired, just give me instructions on what to look for

@bynect
Copy link
Member Author

bynect commented Jul 3, 2024

If someone can test it it would be great 👍🏻

I can test it on Wayland if desired, just give me instructions on what to look for

it would be great if you could check if the input works correctly (mouse clicks for closing etc) and if you notice any graphical discrepancy let me know.
The only difference I noticed is that text is a bit less sharp but maybe it's just me?

@matejdro
Copy link
Contributor

matejdro commented Jul 6, 2024

Only issue I have noticed is that, with scaling enabled, dunst window has bigger horizontal offset from the edge of the screen and the window is smaller. All below screenshots extend to the top right corner of the monitor.

This branch

Scaled monitor:

image

Interestingly enough, after I take a screenshot and Satty opens fullscreen, dunst window will become taller (even before Satty makes second notification):

image

Non-scaled monitor (still suffering from #1316):

image

After I turn off scaling on the other monitor, text is clearer for the non-scaled monitor and position bug disappears:

image

Dunst release

Scaled monitor:

image

Non-scaled monitor:

image

After I turn off scaling on the other monitor, text is clearer:

image

Mouse clicks seem to work fine. I also don't see any discrepancies regarding text quality between this branch and latest dunst release (but you can judge yourself from screenshots). Both monitors are 2560x1440, with 2x scaling on one of the monitors (where specified).

Compositor:

Hyprland, built from branch  at commit 918d8340afd652b011b937d29d5eea0be08467f5  (flake.lock: update).
Date: Tue Jun 25 12:06:02 2024
Tag: v0.41.2, commits: 4886

@bynect
Copy link
Member Author

bynect commented Jul 6, 2024

@matejdro so is the resolution still wrong even with this branch?

Also I can look into the offset problem, probably something was not scaled appropriately

@matejdro
Copy link
Contributor

matejdro commented Jul 10, 2024

Above screenshots are from Hyprland.

On Sway, text look as bad on this branch as with the release:

image

But interestingly enough, on Hyprland, issue appears to be different. As you can see on the screenshots from the previous post, text is still worse when scaling is enabled, but it's not as jagged as on Sway. Maybe Hyprland applies some sort of font smoothing by default, not sure. This is also the case with release version of dunst, so no changes here.

@bynect
Copy link
Member Author

bynect commented Jul 10, 2024

Thanks very much for the feedback. I will investigate this further and make some changes 👍

@bynect
Copy link
Member Author

bynect commented Jul 25, 2024

@matejdro just to let you know. the problem with wayland scaling is that we check for the screen before drawing but on wayland the protocol does not allow that with follow mode. so further changes are needed to this pr for it to work on wayland. maybe it should be done in a seperate pr

@bynect bynect marked this pull request as ready for review December 3, 2024 10:06
@bynect
Copy link
Member Author

bynect commented Dec 3, 2024

I am not sure if this needs more work. I would probably do the scale detection refactor in another pr since it requires wayland backend changes.

Also the graphical effect of cairo_surface_set_device_scale is not as good as I thought due to antialiasing...

@fwsmit
Copy link
Member

fwsmit commented Dec 4, 2024

Can you show what is the visual difference between the two? I don't really understand why the old method would not work on Wayland. Not that using pango device scale is bad, but I'm not sure this should solve a scaling issue on Wayland.
It seems like the problem on Wayland is related to not detecting the scale factor correctly which can be solved by changing the Wayland backend as you mentioned. I thought of some hacky way a while ago where you first draw the surface and then find on which display the surface was drawn and get the right display scale factor. After you might need to redraw. But there might be a better way possible now with protocol updates.

@bynect
Copy link
Member Author

bynect commented Dec 4, 2024

Can you show what is the visual difference between the two? I don't really understand why the old method would not work on Wayland. Not that using pango device scale is bad, but I'm not sure this should solve a scaling issue on Wayland. It seems like the problem on Wayland is related to not detecting the scale factor correctly which can be solved by changing the Wayland backend as you mentioned. I thought of some hacky way a while ago where you first draw the surface and then find on which display the surface was drawn and get the right display scale factor. After you might need to redraw. But there might be a better way possible now with protocol updates.

the problem is the layer protocol like you mentioned. As far I understand it doesn't allow you to know beforehand where you are drawing. The possible solution using this device scale is that you first render at 1x on the surface image (like we already do) and then you scale this surface afterwards.
This in general should be better than scaling everything but somehow the result I get is worse.
Probably skill issue on my part.
Anyway I don't see an easy way to deal with the wayland issue without thorough refactoring

@fwsmit
Copy link
Member

fwsmit commented Dec 5, 2024

the problem is the layer protocol like you mentioned. As far I understand it doesn't allow you to know beforehand where you are drawing.

If you set the output to some value, then you know the surface will be drawn to this output. The thing is that if follow=mouse or follow=keyboard is set, we set the output to NULL, indicating to the compositor it can decide where to place the notification. This means you don't know where the notification will end up until after it's shown. When a single output it set in the configuration, it is always possible to determine beforehand on which output the notification will end up and there should be no scaling issues.

So the only case where there should be scaling issues is when follow=keyboard/mouse AND there are multiple outputs with different scales. We could mention this shortcoming in the documentation or work around it in a hacky way.

This PR will not solve the mentioned issue, it only makes the code a bit cleaner.

@fwsmit
Copy link
Member

fwsmit commented Dec 5, 2024

if the offset problem, as mentioned in the testing above is fixed, I think this can be merged.

@b0ch3nski
Copy link

b0ch3nski commented Dec 5, 2024

scaling issues is when follow=keyboard/mouse AND there are multiple outputs with different scales.

This is exactly what is happening in my case 🙁

@bynect bynect marked this pull request as draft December 10, 2024 00:42
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

Successfully merging this pull request may close these issues.

5 participants