slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.2k stars 583 forks source link

Wobbly resize (missing or inserted pixel rows/columns) when animation_tick() is used somewhere in an app and using winit #6259

Open jturcotte opened 3 weeks ago

jturcotte commented 3 weeks ago

It's only visible during resize, once I stop resizing the rendering looks correct. Once I close the window containing animation_tick() (with the red text), the other window starts behaving correctly.

rec

main.rs

use slint::slint;

slint! {
    export component Window inherits Window {
        Rectangle {
            // Comment out this line and the text wobbling disappears.
            x: animation_tick() / 1ms * 1px;
        }
        TextInput {
            single-line: false;
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
            color: red;
        }
    }
}
slint! {
    // animation_tick affects this window even though it's in the other one.
    export component Window2 inherits Window {
        TextInput {
            single-line: false;
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
        }
    }
}
fn main() {
    Window::new().unwrap().show().unwrap();
    Window2::new().unwrap().show().unwrap();
    slint::run_event_loop().unwrap();
}

Cargo.toml

[package]
name = "wobble"
edition = "2021"

[build-dependencies]
slint-build = "1"
[dependencies.slint]
version = "1.7.2"
default-features = false
# Not reproducible with the Qt backend
features = ["compat-1-2", "backend-winit", "renderer-winit-femtovg"]

[[bin]]
name = "wobble"
path = "main.rs"
tronical commented 2 weeks ago

What operating system and windowing system are you using?

tronical commented 2 weeks ago

If it's x11, then this would probably be a duplicate of #5050 . If it's wayland, then maybe this is a bad interaction with the frame event.

What's the CPU usage during this? Is it 100%?

jturcotte commented 2 weeks ago

This is on Wayland. The CPU usage isn't very high, 5% maybe.

jturcotte commented 2 weeks ago

What operating system and windowing system are you using?

Ubuntu 24.04 with Sway WM.

tronical commented 2 weeks ago

Thanks for the quick confirmation.

ogoffart commented 2 weeks ago

@tronical what is the problem here? is that not an issue with the renderer?

tronical commented 2 weeks ago

I don't think it is. The renderer merely renders into the sub-surface and posts to the compositor, but when that happens in relation to the user input, decorations, and when the compositor shows both together is I'd say part of the wayland protocol interaction. My guess is that the frame callback doesn't work well in conjunction with multiple windows somehow, as when the animation tick window (which triggers frame throttling) is not visible, it's smooth.

jturcotte commented 2 weeks ago

I also see the issue if I use a single window with animation_tick in it.

I put two windows just to show that the problem bleeds to other windows too.

edit: No sorry I tried again and it indeed requires the two windows.

tronical commented 2 weeks ago

(FWIW, I still can't reproduce it on my sway installation, but that doesn't say much)

I wonder if the effect is any better if shm is used instead of wayland-egl. Could you try with SLINT_BACKEND=winit-software ?

jturcotte commented 2 weeks ago

I tried winit-skia before and I could reproduce it, just tried with winit-software and it's also reproducible.

tronical commented 2 weeks ago

Thanks for checking :). Makes me think even more that this is more frame related. BTW, do you see the same issue under mutter/gnome/ubuntu, or just sway?

jturcotte commented 2 weeks ago

I didn't try Gnome yet, I'll give it a try this weekend.

jturcotte commented 2 weeks ago

I can reproduce it in Gnome with both Wayland and Xorg.

In xorg however I don't see the horizontal compression, only the rendered surface being offset vertically from the top-left corner as seen in the GIF above (but slightly different, the void left isn't white).

jturcotte commented 3 days ago

I don't know if it's possible here, but the visual effect reminds me issues I faced elsewhere when drawing wasn't done on the right back buffer.

tronical commented 3 days ago

Hmm, this debunks another theory I had: that we’re resizing the surface at the wrong time and it ends up out of sync with the decoration (client side). But if this also happens with x11…. Maybe it’s a bug in the graphics driver?

jturcotte commented 3 days ago

I asked chatgpt to analyze the WAYLAND_DEBUG=1 logs with and without animation_tick() and the surface seem to be the wrong size (2548, 572 vs 2548, 569). It seems to make sense but I don't know the protocol enough to understand it.

https://chatgpt.com/share/67083f7d-eb38-800e-8395-0f89a3742fd3

[2225575.908] xdg_surface@38.configure(653070) [2225576.049] -> xdg_surface@38.ack_configure(653070) [2225576.107] -> wl_surface@37.set_opaque_region(nil) [2225576.133] -> xdg_surface@38.set_window_geometry(0, 0, 2548, 572) [2225576.159] -> wp_viewport@41.set_destination(2548, 572) [2225576.362] wl_buffer@60.release() [2225576.373] -> wl_buffer@60.destroy() [2225576.386] wl_callback@55.done(372062969) [2225580.330] wl_display@1.delete_id(51) [2225580.349] wl_display@1.delete_id(58) [2225581.818] -> wl_surface@37.frame(new id wl_callback@55) [2225582.114] -> wl_surface@37.frame(new id wl_callback@59) [2225582.131] -> zwp_linux_dmabuf_v1@36.create_params(new id zwp_linux_buffer_params_v1@61) [2225582.166] -> zwp_linux_buffer_params_v1@61.add(fd 17, 0, 0, 10240, 16777216, 8) [2225582.182] -> zwp_linux_buffer_params_v1@61.add(fd 20, 1, 5898240, 1280, 16777216, 8) [2225582.192] -> zwp_linux_buffer_params_v1@61.add(fd 21, 2, 5922816, 64, 16777216, 8) [2225582.203] -> zwp_linux_buffer_params_v1@61.create_immed(new id wl_buffer@57, 2548, 569, 875713089, 0) [2225582.213] -> zwp_linux_buffer_params_v1@61.destroy() [2225582.221] -> wl_surface@37.attach(wl_buffer@57, 0, 0) [2225582.229] -> wl_surface@37.damage(0, 0, 2147483647, 2147483647) [2225582.237] -> wl_surface@37.commit() [2225582.421] wl_callback@51.done(372062973) [2225582.612] -> xdg_toplevel@39.set_title("Slint Window") [2225582.647] wl_display@1.delete_id(60) [2225582.659] wl_display@1.delete_id(61) [2225582.718] wl_buffer@62.release() [2225582.729] wl_callback@58.done(372062973) [2225583.788] wl_display@1.delete_id(55) [2225583.794] wl_display@1.delete_id(59) [2225584.918] -> wl_surface@35.frame(new id wl_callback@58) [2225585.076] -> wl_surface@35.frame(new id wl_callback@61) [2225585.085] -> wl_surface@35.attach(wl_buffer@62, 0, 0) [2225585.093] -> wl_surface@35.damage(0, 0, 2147483647, 2147483647) [2225585.101] -> wl_surface@35.commit() [2225585.189] wl_callback@55.done(372062977)