You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When screencasting windows that aren't visible (e.g. scrolled far away, or on a different workspace entirely), they are only refreshed at 1Hz. This is because of ed8a6af. Prior to that commit, they wouldn't be refreshed at all. Windows that aren't visible aren't refreshed every frame, because that's wasteful. This calculation doesn't take into consideration the new per-window screencasting introduced just before 0.1.7 was tagged. So, those captured windows, when on a separate workspace or otherwise not within the current viewport, look really stuttery on a screencast. But they should be considered as visible. This likely went unnoticed due to testing windowed screencasting on mostly static windows that change when interacted with (and always have focus as a result). To reproduce it, play a youtube video, and open Discord on a separate workspace. Screenshare that browser tab in Discord and observe the stuttery mess it becomes.
Discovery
Originally discovered by @yuu-fur (@yuu.dev:catgirl.cloud), who uses a laptop with a NVIDIA-brand dedicated GPU and a hybrid setup. We both thought it might be an NVIDIA issue, but it turned out not to be the case. Changing which GPU anything runs on doesn't help. I later reproduced the issue on my own system, which runs an AMD GPU, completely ruling out the possibility of it being an NVIDIA issue. Since this was happening on Vesktop, i thought it might be Vencord/Vesktop#629 which is caused by an underlying Chromium bug, but his issue persists in Firefox-based browsers too (Librewolf; tested with web Discord) so that's not it either. We eventually realized it was highly correlated to window focus, and i remembered that commit from way back about refreshing off-screen windows, and i tested various ways for a window to leave the viewport, all of which resulted in the same stutter. This led me to look into the underlying code.
Workaround
Do not use this workaround. It wastes resources by refreshing every window every frame. A real patch that only refreshes the relevant screencapture windows is available. You can expand this to see what i originally had to say about the workaround.
I wrote this patch to workaround the issue. It does not fundamentally solve the problem, because it just increases the refresh rate of off-screen windows. You can change out the / 60 with whatever your refresh rate is. This patch will cause more resource usage, including degraded battery life. It basically disables a power-saving feature (or rather, heavily nerfs it). I created it by looking at ed8a6af and just changing the timer values. A Duration::ZERO is valid for how this is used. I didn't try this on my own system, but @yuu-fur did and reports that it worked well and seems to solve the issue (yay! high-refresh-rate screencasting!)
I don't recommend anyone really run this patch, especially not on a battery-constrained device (think of your battery life! your poor battery!), but it basically confirms the root cause is what i described at the top. You can apply it in my niri-flake by saving this patch to a file niri.patch and then setting programs.niri.package = pkgs.niri-unstable.override { patches = [ ./niri.patch ]; };
diff --git a/src/niri.rs b/src/niri.rs
index 664aea6..9ae8505 100644
--- a/src/niri.rs+++ b/src/niri.rs@@ -147,7 +147,7 @@ const CLEAR_COLOR_LOCKED: [f32; 4] = [0.3, 0.1, 0.1, 1.];
// We'll try to send frame callbacks at least once a second. We'll make a timer that fires once a
// second, so with the worst timing the maximum interval between two frame callbacks for a surface
// should be ~1.995 seconds.
-const FRAME_CALLBACK_THROTTLE: Option<Duration> = Some(Duration::from_millis(995));+const FRAME_CALLBACK_THROTTLE: Option<Duration> = Some(Duration::ZERO);
pub struct Niri {
pub config: Rc<RefCell<Config>>,
@@ -1607,10 +1607,10 @@ impl Niri {
event_loop
.insert_source(
- Timer::from_duration(Duration::from_secs(1)),+ Timer::from_duration(Duration::from_secs(1) / 60),
|_, _, state| {
state.niri.send_frame_callbacks_on_fallback_timer();
- TimeoutAction::ToDuration(Duration::from_secs(1))+ TimeoutAction::ToDuration(Duration::from_secs(1) / 60)
},
)
.unwrap();
Description
When screencasting windows that aren't visible (e.g. scrolled far away, or on a different workspace entirely), they are only refreshed at 1Hz. This is because of ed8a6af. Prior to that commit, they wouldn't be refreshed at all. Windows that aren't visible aren't refreshed every frame, because that's wasteful. This calculation doesn't take into consideration the new per-window screencasting introduced just before 0.1.7 was tagged. So, those captured windows, when on a separate workspace or otherwise not within the current viewport, look really stuttery on a screencast. But they should be considered as visible. This likely went unnoticed due to testing windowed screencasting on mostly static windows that change when interacted with (and always have focus as a result). To reproduce it, play a youtube video, and open Discord on a separate workspace. Screenshare that browser tab in Discord and observe the stuttery mess it becomes.
Discovery
Originally discovered by @yuu-fur (
@yuu.dev:catgirl.cloud
), who uses a laptop with a NVIDIA-brand dedicated GPU and a hybrid setup. We both thought it might be an NVIDIA issue, but it turned out not to be the case. Changing which GPU anything runs on doesn't help. I later reproduced the issue on my own system, which runs an AMD GPU, completely ruling out the possibility of it being an NVIDIA issue. Since this was happening on Vesktop, i thought it might be Vencord/Vesktop#629 which is caused by an underlying Chromium bug, but his issue persists in Firefox-based browsers too (Librewolf; tested with web Discord) so that's not it either. We eventually realized it was highly correlated to window focus, and i remembered that commit from way back about refreshing off-screen windows, and i tested various ways for a window to leave the viewport, all of which resulted in the same stutter. This led me to look into the underlying code.Workaround
Do not use this workaround. It wastes resources by refreshing every window every frame. A real patch that only refreshes the relevant screencapture windows is available. You can expand this to see what i originally had to say about the workaround.
I wrote this patch to workaround the issue. It does not fundamentally solve the problem, because it just increases the refresh rate of off-screen windows. You can change out the
/ 60
with whatever your refresh rate is. This patch will cause more resource usage, including degraded battery life. It basically disables a power-saving feature (or rather, heavily nerfs it). I created it by looking at ed8a6af and just changing the timer values. ADuration::ZERO
is valid for how this is used. I didn't try this on my own system, but @yuu-fur did and reports that it worked well and seems to solve the issue (yay! high-refresh-rate screencasting!)I don't recommend anyone really run this patch, especially not on a battery-constrained device (think of your battery life! your poor battery!), but it basically confirms the root cause is what i described at the top. You can apply it in my
niri-flake
by saving this patch to a fileniri.patch
and then settingprograms.niri.package = pkgs.niri-unstable.override { patches = [ ./niri.patch ]; };
Patch
System Information
how many times can you mention your favorite commit in just one issue?
The text was updated successfully, but these errors were encountered: