Skip to content

Update screencast_thread.rs for support fps limit#152

Draft
meocoder31099 wants to merge 7 commits intopop-os:masterfrom
meocoder31099:master
Draft

Update screencast_thread.rs for support fps limit#152
meocoder31099 wants to merge 7 commits intopop-os:masterfrom
meocoder31099:master

Conversation

@meocoder31099
Copy link

#149
Needs testing. I am using std::thread::sleep to block the thread until the next frame capture time. I'm not sure if it will cause any issues.

None => return Err(anyhow::anyhow!("failed to use shm capture to get size")),
};

let framerate = 60; // Default framerate. XXX is there a better way?
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we simply shouldn't wait by default. The compositor won't do unlimited frame rates, but synchronize captures to the screen's frame rate.

This is also why I am not sure this approach in general is such a good idea, as the compositor could potentially introduce another delay, if we send the capture request earlier in the redraw cycle, after we already waited to hit the target frame rate.

Worse, if we wait the full duration, it might happen that the request reaches a busy compositor to late to be effective for the current draw cycle, potentially cutting our frame rate in half.

So a good implementation of this should imo, track the current frame rate and only if we are ahead of the target, delay the next frame by a full frame minus some safety margin.

Copy link
Author

Choose a reason for hiding this comment

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

I noticed something that seems strange. When I capture a 60Hz screen, if the screen is mostly empty, the captured FPS is approximately 47 FPS. However, if I move the mouse, the FPS immediately drops significantly. This effect is even more noticeable when watching a video (whether it's 24 FPS or 60 FPS), as the captured FPS remains around 23-24 FPS. I don't understand what is causing this behavior.

Copy link
Member

Choose a reason for hiding this comment

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

This effect is even more noticeable when watching a video (whether it's 24 FPS or 60 FPS), as the captured FPS remains around 23-24 FPS. I don't understand what is causing this behavior.

Cosmic-comp doesn't draw at a constant frame rate, when nothing on the screen changes. So sampling from previous frame times doesn't work. You also shouldn't assume the refresh rate of the modes given by wl_output actually match the targeted framerate, as VRR and other things can mess with it.

The frame rate hint should purely be used to trottle further requests, should you receive frames too quickly.

Copy link
Author

Choose a reason for hiding this comment

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

I assume that only throttling when we receive frames too quickly would be fine if the framerate is at a sufficiently high level (the higher the framerate, the better). However, suppose we have a very low framerate, such as 2 frames per second. We would quickly reach the limit of 2 frames, and then the next frame would have to wait for a certain period until the start of the next cycle.

As a result, we would encounter a situation where frames are distributed unevenly within a capture cycle. For example, if the compositor draws 60 different frames within one capture cycle, and we only take ~100ms to capture the first 2 frames, we would then have to wait ~900ms until the next capture cycle, causing all frames drawn during this period to be skipped.

I want a more even distribution of captured frames within a cycle. So, is there a threshold value to consider as a low frequency, where we would wait for the appropriate moment before requesting a frame capture? In other cases, we would only throttle if we receive frames too quickly.

Copy link
Member

@Drakulix Drakulix Mar 26, 2025

Choose a reason for hiding this comment

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

I want a more even distribution of captured frames within a cycle.

Looking at cosmic-comp's code again, frame pacing should be possible. A new capture request will queue a redraw, even if that happens to be empty (no changes since the last draw), it will update captures.

So worse case the request will still have to wait until the next redraw, which might be a full vblank cycle.

But I guess delaying by targeted frame-rate minus some time to allow processing in the compositor should work fine. If nothing else, you could wait half the targeted frame rate, submit and then make up for the rest of the time by throttling. The code should just avoid to unconditionally wait the full frame time, as that will guarantee you don't hit the frame rate in the first place.

But the code shouldn't assume the compositor's refresh rate as there is really no stable source for that kind of information.

meocoder31099 added a commit to meocoder31099/xdg-desktop-portal-cosmic that referenced this pull request Mar 23, 2025
- Read the refresh rate of the captured screen and assign it to the `framerate` of `StreamData`.  
- Optimize the waiting mechanism for the next frame based on @Drakulix's advice  
  [advice](pop-os#152 (comment)) by prioritizing frame capture and sending it to PipeWire first. Then, calculate the time taken to capture that frame, and if we are ahead of the next frame's capture time, wait for approximately `delay_ns = target_ns - frame_took_ns`.
@meocoder31099 meocoder31099 reopened this Feb 6, 2026
@meocoder31099 meocoder31099 marked this pull request as ready for review February 6, 2026 16:59
@meocoder31099 meocoder31099 marked this pull request as draft February 6, 2026 16:59
@meocoder31099
Copy link
Author

@Drakulix could you review it?

@Drakulix Drakulix requested a review from ids1024 February 12, 2026 17:13
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.

2 participants