mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-27 00:15:59 +01:00
ab8ff54f4c
The goal is to control the rate of capture while in screencast, as it can represent a performance issue and can cause input lag and the feeling of having a laggy mouse. This commit addresses the issue reported in #66. The code measures the time elapsed to make a single screen capture, and calculates how much to wait for the next capture to achieve the targeted frame rate. To delay the capturing of the next frame, the code introduces timers into the event loop based on the event loop in https://github.com/emersion/mako Added a command-line argument and an entry in the config file as well for the max FPS. The default value is 0, meaning no rate control. Added code to measure the average FPS every 5 seconds and print it with DEBUG level.
70 lines
1.9 KiB
C
70 lines
1.9 KiB
C
#include "fps_limit.h"
|
|
#include "logger.h"
|
|
#include "timespec_util.h"
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
|
|
#define FPS_MEASURE_PERIOD_SEC 5.0
|
|
|
|
void measure_fps(struct fps_limit_state *state, struct timespec *now);
|
|
|
|
void fps_limit_measure_start(struct fps_limit_state *state, double max_fps) {
|
|
if (max_fps <= 0.0) {
|
|
return;
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &state->frame_last_time);
|
|
}
|
|
|
|
uint64_t fps_limit_measure_end(struct fps_limit_state *state, double max_fps) {
|
|
if (max_fps <= 0.0) {
|
|
return 0;
|
|
}
|
|
|
|
// `fps_limit_measure_start` was not called?
|
|
assert(!timespec_is_zero(&state->frame_last_time));
|
|
|
|
struct timespec now;
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
int64_t elapsed_ns = timespec_diff_ns(&now, &state->frame_last_time);
|
|
|
|
measure_fps(state, &now);
|
|
|
|
int64_t target_ns = (1.0 / max_fps) * TIMESPEC_NSEC_PER_SEC;
|
|
int64_t delay_ns = target_ns - elapsed_ns;
|
|
if (delay_ns > 0) {
|
|
logprint(TRACE, "fps_limit: elapsed time since the last measurement: %u, "
|
|
"target %u, should delay for %u (ns)", elapsed_ns, target_ns, delay_ns);
|
|
return delay_ns;
|
|
} else {
|
|
logprint(TRACE, "fps_limit: elapsed time since the last measurement: %u, "
|
|
"target %u, target not met (ns)", elapsed_ns, target_ns);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void measure_fps(struct fps_limit_state *state, struct timespec *now) {
|
|
if (timespec_is_zero(&state->fps_last_time)) {
|
|
state->fps_last_time = *now;
|
|
return;
|
|
}
|
|
|
|
state->fps_frame_count++;
|
|
|
|
int64_t elapsed_ns = timespec_diff_ns(now, &state->fps_last_time);
|
|
|
|
double elapsed_sec = (double) elapsed_ns / (double) TIMESPEC_NSEC_PER_SEC;
|
|
if (elapsed_sec < FPS_MEASURE_PERIOD_SEC) {
|
|
return;
|
|
}
|
|
|
|
double avg_frames_per_sec = state->fps_frame_count / elapsed_sec;
|
|
|
|
logprint(DEBUG, "fps_limit: average FPS in the last %0.2f seconds: %0.2f",
|
|
elapsed_sec, avg_frames_per_sec);
|
|
|
|
state->fps_last_time = *now;
|
|
state->fps_frame_count = 0;
|
|
}
|