Open FabianLars opened 1 year ago
I tried both wry and tauri but the problem is I get the same resizing performance. But your Tauri app looks worse than mine, like crashing and freezing. I don't have that.
Wry on the left, tauri on the right - Release builds
Yeah, it used to be the same for me a while back. but some months ago it changed to whatever the hell is going on in the video i posted (maybe it's something specific to my app idk). Note that it's not that bad, but OBS didn't like converting 144hz to a 30fps video i guess.
i guess on top of that we could use this issue as an continuation/extension of https://github.com/tauri-apps/tauri/issues/4012 🤷
I also tried with this sample code sample.rs. the issue is still there, and the resizing performance is bad. Probably an issue with Webview2 itself
my webview 2 version is 110.0.1587.46
Probably an issue with Webview2 itself
Don't get me wrong, resizing webview2, or chromium in general is incredibly slow, at least if hardware acceleration is enabled. There are just 2 issues on top of. 1) the one in my video, where it's much slower in tauri than in wry (though as we know it's not as must of a difference for everyone) 2) the webview2 background color setting we thought would help us here does not work for us. We unfortunately have to change the color of the window itself which is also a bit tricky. - i think i documented my thoughts and experiments somewhere else, at least on discord 🤔
@FabianLars yeah, To my knowledge microsoft edge also uses webview2 but It feels like It performs way better than wry, tauri, and the code I posted which uses only the windows API nothing else.
To my knowledge microsoft edge also uses webview2
More like the other way around, webview2 is a modified edge browser, but same thing.
but It feels like It performs way better than wry, tauri, and the code I posted which uses only the windows API nothing else.
yep, something is wrong somewhere. But it's a really weird thing. like, we basically use the same apis like the ms employee in your issue said, etc. And then another weird thing is that Wails (a similar project to tauri but written in Go) was just as laggy as tauri last time i tested it (tho less obvious because they change the window color) - well, maybe not that weird if they make the same mistake we do but whatever.
I tried adding delay to updating size of webview. I think It works a little better. What do you think? the delay I show in the video is 10ms, I just tried with 2ms and both works pretty good.
Without Delay
With Delay
Yeah i guess that's a bit better indeed. Though i'm not aware of the possible consequences the change could have, maybe @amrbashir does, and/or maybe we need some more testing to be sure that wouldn't break anything (or maybe we find the actual cause&solution along the way :D )
@FabianLars Yeah, It feels like this will break something. I just wanted to know if it feels better or if I'm going crazy
Maybe Windows triggers resize event with the same values twice or something? I don't know. or maybe because we try to resize webview way too quickly.
This is a project of mine. The difference in performance is easier to see here. Both projects are in release mode, I reduced the delay to 2ms.
WindowsAndMessaging::WM_SIZE => {
std::thread::sleep(Duration::from_millis(2));
let size = get_window_size(hwnd);
unsafe {
webview
.controller
.0
.SetBounds(RECT {
left: 0,
top: 0,
right: size.cx,
bottom: size.cy,
})
.unwrap();
}
*frame.size.lock().expect("lock size") = size;
LRESULT::default()
}
With Delay
Without Delay
Good findings and a strange one I must say. I just tested and can confirm it works and it even works with just 1ms
delay too, However, I don't think we should have this by default at all because the thread could sleep longer than expected and have unknown side-effects in some apps, see std::tread::sleep
:
The thread may sleep longer than the duration specified due to scheduling specifics or platform-dependent functionality. It will never sleep less.
That said, I am fine with adding it behind an option or a feature-flag but not the default
I'm facing with the same problem. @metkm Can you please help me with applying the same edit? I'm newbie to the Tauri and Rust and wondering where I should put this code to make it work 😓
@cogscides what I did was just for now is
fn main() {
tauri::Builder::default()
.setup(|app| {
let Some(window) = app.get_window("main") else {
return Ok(())
};
window.on_window_event(|event| {
match event {
WindowEvent::Resized(..) => {
std::thread::sleep(std::time::Duration::from_millis(1))
}
_ => {}
}
});
Ok(())
})
.invoke_handler(tauri::generate_handler![])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
But be careful you are blocking the thread
Moving it back here since the original issue is about tauri vs wry performance and still not fixed.
@metkm feel free to open an issue or a PR to wry for the hack you found.
Am i crazy or does 1 micro second have the same effect as 1 milisecond?
Like, from_micros(1))
"fixes" it in the same way from_millis
does.
Edit: Same for from_nanos(1)
actually
@FabianLars yeah I feel like they have the same effect. I don't know what the default sleep duration should be, or maybe we can leave that to the developer.
Maybe I should reactive this issue again in the webview2 repo
well, i mean at least in rust there's no shorter duration than a nano second right? so imo we should just go with that because it has the least influence on the other components compared to not sleeping if that makes sense?
I saw tauri-apps/wry#892 and I feel like this better to put in tauri-runtime-wry instead? Also it's better to add some comment about why we need it.
@wusyong seems like we don't need to add it in wry or tauri after-all, users could add this in their app logic
tauri::Builder::default()
.on_window_event(|e| {
if let WindowEvent::Resized(_) = e.event() {
std::thread::sleep(std::time::Duration::from_nanos(1));
}
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
Honestly not the biggest fan of not including it in tauri in some way since virtually all windows users complain about the laggy resizing.
std::thread::sleep
could sleep longer than requested so I'd rather let users to choose to opt-in rather than opt-out
I'm using Windows 11, I don't experience the same lag in resizing at the moment. I know that others are encountering it in Windows 11... but here is what it looks like without any hacks:
https://user-images.githubusercontent.com/64731/224395458-9a883066-b166-4489-bdbd-463d066d25f7.mp4
It has low frame counts but that's only because of the video. It's smooth for me.
The current app code is here: https://github.com/Ciantic/winvd-monitoring (works only on Windows 11 because of my desktop library)
Just wanna chime in here with that it's very weird that at least on Windows 11 if you put the window to the side so that it covers half the screen or just maximize / unmaximize it resizes perfectly fine, even more fluid than with the 1 nano second sleep workaround, which suggests that there is in fact a solution to this, we just don't know what it is.
Also, on my machine I have 2 graphics cards, one crappy and one good, and when I move the window to the monitor with the crappy card it's very clearly a difference in how effective the workaround is, suggesting part of this is just related to hardware, and that there is in fact a better solution since e.g. maximize / unmaximize performs much better even on the crappy card.
Reach out to Microsoft possibly?
I remember having this issue with a normal Win32 window, this happens if the window receives too many event calls, I fixed this by render while the resize event was called and not after the event loop (which you would usually do).
allthough i don't know if this applies here aswell. just giving a piece of what i've experienced.
So, to fix this you would either have to render everything during the resize event or have some sort of "deadline" which if has been hit, will enqueue all future events to a new frame (and should cancel/ignore all non important events) and continue with the rendering
(a theory) the sleep causes a context switch and cancels all the Win32 resize events (except the very last one sent) This is also why https://github.com/tauri-apps/tauri/issues/6322#issuecomment-1437047841 works
Similar issue I noticed on linux build, - resizing the window reduces React app performance significantly
So, to fix this you would either have to render everything during the resize event or have some sort of "deadline" which if has been hit, will enqueue all future events to a new frame (and should cancel/ignore all non important events) and continue with the rendering
A test of limiting the rate of resizing webview:
[package]
name = "wry-test"
version = "0.1.0"
edition = "2021"
[dependencies]
winit = { version = "0.29.7", features = ["rwh_05"] }
wry = "0.35.1"
use std::time::{Duration, Instant};
use winit::event::{Event, WindowEvent};
use winit::event_loop::EventLoop;
use winit::window::WindowBuilder;
use wry::{Rect, WebViewBuilder};
fn main() -> wry::Result<()> {
let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new()
.with_title("Hello World")
.build(&event_loop)
.unwrap();
let webview = WebViewBuilder::new_as_child(&window)
.with_url("https://tauri.app")?
.build()?;
let mut resize_request = None;
let mut last_resize_time = Instant::now();
event_loop
.run(move |event, elwt| {
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
println!("The close button was pressed; stopping");
elwt.exit();
}
Event::AboutToWait => {
if let Some(bound) = resize_request.take() {
webview.set_bounds(bound);
}
window.request_redraw();
}
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
let bound = Rect {
x: 0,
y: 0,
width: size.width,
height: size.height,
};
// My monitor refresh rate: 144
if last_resize_time.elapsed() > Duration::from_millis(1000 / 144) {
webview.set_bounds(bound);
resize_request = None;
last_resize_time = Instant::now();
} else {
resize_request = Some(bound);
}
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {}
_ => (),
}
})
.expect("event loop run failed");
Ok(())
}
And it is fast as the Edge browser.
Without rate limitation:
https://github.com/tauri-apps/tauri/assets/19628575/1d68c2fa-1d6f-4b3a-92f0-50d609ff49d8
With rate limitation:
https://github.com/tauri-apps/tauri/assets/19628575/e27d08aa-6670-4193-8543-fa20f5024b9a
Describe the bug
We all know that Chromium is super slow to resize its content, it's present in all Chromium browsers too, but while trying out a few workarounds to make it less noticeable, like setting the window background color via win32 apis (changing the webview2 background doesn't change anything btw because the webview itself is not resized in time), i noticed that this is pretty much no problem in Wry but it got even worse in Tauri than the last time i really paid attention to it. Here's a recording. Its resolution and fps makes it look a bit worse than it actually is.
https://user-images.githubusercontent.com/30730186/210389507-8367d374-c65f-4238-9e76-7aea3d65ffb4.mp4
Note that i already disabled Tauri's window event handlers in its source code for that recording - no noticeable difference. The 2 apps in the video are release builds pointing to my local dev server. debug builds, and release builds with bundled artifacts have the same behavior.
I could not reproduce this issue on Linux.
Reproduction
Build literally any app on Windows. It's present even in the most lightweight vanillajs apps.
Expected behavior
i don't expect Tauri to be as fast as Wry but it shouldn't feel like my computer is crashing.
Platform and versions
Environment › OS: Windows 10.0.19045 X64 › Webview2: 108.0.1462.54 › MSVC: › Node.js: 18.12.1 › npm: 8.19.2 › pnpm: 7.21.0 › yarn: 1.22.19 › rustup: 1.25.1 › rustc: 1.66.0 › cargo: 1.66.0 › Rust toolchain: stable-x86_64-pc-windows-msvc
Packages › @tauri-apps/cli [NPM]: 1.2.2 › @tauri-apps/api [NPM]: 1.2.0 › tauri [RUST]: 1.2.3, (overwritten with local path for testing but released version has the same problem) › tauri-build [RUST]: 1.2.1, › tao [RUST]: 0.15.8, › wry [RUST]: 0.23.4,
App › build-type: bundle › CSP: unset › distDir: ../dist › devPath: http://localhost:5173/ › framework: React › bundler: Vite
App directory structure ├─ dist ├─ node_modules ├─ src └─ src-tauri
Stack trace
No response
Additional context
I also added some window event logging in Wry's source code for testing and that looks jittery too when used in Tauri.