Portal: sync capture to frame update

This commit is contained in:
dec05eba
2024-09-15 04:22:00 +02:00
parent f53d7b30b1
commit f6f8fdb33c
6 changed files with 53 additions and 11 deletions

View File

@@ -25,6 +25,8 @@ struct gsr_capture {
bool (*uses_external_image)(gsr_capture *cap); /* can be NULL. If NULL, return false */ bool (*uses_external_image)(gsr_capture *cap); /* can be NULL. If NULL, return false */
bool (*set_hdr_metadata)(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata); /* can be NULL. If NULL, return false */ bool (*set_hdr_metadata)(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata); /* can be NULL. If NULL, return false */
uint64_t (*get_window_id)(gsr_capture *cap); /* can be NULL. Returns 0 if unknown */ uint64_t (*get_window_id)(gsr_capture *cap); /* can be NULL. Returns 0 if unknown */
bool (*is_damaged)(gsr_capture *cap); /* can be NULL */
void (*clear_damage)(gsr_capture *cap); /* can be NULL */
void (*destroy)(gsr_capture *cap, AVCodecContext *video_codec_context); void (*destroy)(gsr_capture *cap, AVCodecContext *video_codec_context);
void *priv; /* can be NULL */ void *priv; /* can be NULL */

View File

@@ -65,6 +65,7 @@ typedef struct {
struct spa_video_info format; struct spa_video_info format;
int server_version_sync; int server_version_sync;
bool negotiated; bool negotiated;
bool damaged;
struct { struct {
bool visible; bool visible;
@@ -105,5 +106,7 @@ void gsr_pipewire_deinit(gsr_pipewire *self);
/* |plane_fds| should be at least GSR_PIPEWIRE_DMABUF_MAX_PLANES in size */ /* |plane_fds| should be at least GSR_PIPEWIRE_DMABUF_MAX_PLANES in size */
bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, gsr_pipewire_region *region, gsr_pipewire_region *cursor_region, int *plane_fds, int *num_plane_fds, bool *using_external_image); bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, gsr_pipewire_region *region, gsr_pipewire_region *cursor_region, int *plane_fds, int *num_plane_fds, bool *using_external_image);
bool gsr_pipewire_is_damaged(gsr_pipewire *self);
void gsr_pipewire_clear_damage(gsr_pipewire *self);
#endif /* GSR_PIPEWIRE_H */ #endif /* GSR_PIPEWIRE_H */

View File

@@ -374,6 +374,16 @@ static bool gsr_capture_portal_uses_external_image(gsr_capture *cap) {
return true; return true;
} }
static bool gsr_capture_portal_is_damaged(gsr_capture *cap) {
gsr_capture_portal *self = cap->priv;
return gsr_pipewire_is_damaged(&self->pipewire);
}
static void gsr_capture_portal_clear_damage(gsr_capture *cap) {
gsr_capture_portal *self = cap->priv;
gsr_pipewire_clear_damage(&self->pipewire);
}
static void gsr_capture_portal_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) { static void gsr_capture_portal_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
(void)video_codec_context; (void)video_codec_context;
gsr_capture_portal *cap_portal = cap->priv; gsr_capture_portal *cap_portal = cap->priv;
@@ -411,6 +421,8 @@ gsr_capture* gsr_capture_portal_create(const gsr_capture_portal_params *params)
.capture_end = gsr_capture_portal_capture_end, .capture_end = gsr_capture_portal_capture_end,
.get_source_color = gsr_capture_portal_get_source_color, .get_source_color = gsr_capture_portal_get_source_color,
.uses_external_image = gsr_capture_portal_uses_external_image, .uses_external_image = gsr_capture_portal_uses_external_image,
.is_damaged = gsr_capture_portal_is_damaged,
.clear_damage = gsr_capture_portal_clear_damage,
.destroy = gsr_capture_portal_destroy, .destroy = gsr_capture_portal_destroy,
.priv = cap_portal .priv = cap_portal
}; };

View File

@@ -130,8 +130,10 @@ bool gsr_damage_set_target_monitor(gsr_damage *self, const char *monitor_name) {
} }
memset(&self->monitor, 0, sizeof(self->monitor)); memset(&self->monitor, 0, sizeof(self->monitor));
if(!get_monitor_by_name(self->egl, GSR_CONNECTION_X11, monitor_name, &self->monitor)) if(strcmp(monitor_name, "screen") != 0 && strcmp(monitor_name, "screen-direct") != 0 && strcmp(monitor_name, "screen-direct-force") != 0) {
fprintf(stderr, "gsr warning: gsr_damage_set_target_monitor: failed to find monitor: %s\n", monitor_name); if(!get_monitor_by_name(self->egl, GSR_CONNECTION_X11, monitor_name, &self->monitor))
fprintf(stderr, "gsr warning: gsr_damage_set_target_monitor: failed to find monitor: %s\n", monitor_name);
}
if(self->window) if(self->window)
XSelectInput(self->egl->x11.dpy, self->window, 0); XSelectInput(self->egl->x11.dpy, self->window, 0);

View File

@@ -980,7 +980,7 @@ static void usage_full() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, " -fm Framerate mode. Should be either 'cfr' (constant frame rate), 'vfr' (variable frame rate) or 'content'. Optional, set to 'vfr' by default.\n"); fprintf(stderr, " -fm Framerate mode. Should be either 'cfr' (constant frame rate), 'vfr' (variable frame rate) or 'content'. Optional, set to 'vfr' by default.\n");
fprintf(stderr, " 'vfr' is recommended for recording for less issue with very high system load but some applications such as video editors may not support it properly.\n"); fprintf(stderr, " 'vfr' is recommended for recording for less issue with very high system load but some applications such as video editors may not support it properly.\n");
fprintf(stderr, " 'content' is currently only supported on X11. The 'content' option matches the recording frame rate to the captured content.\n"); fprintf(stderr, " 'content' is currently only supported on X11 or when using portal capture option. The 'content' option matches the recording frame rate to the captured content.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, " -bm Bitrate mode. Should be either 'auto', 'qp' (constant quality) or 'vbr' (variable bitrate). Optional, set to 'auto' by default which defaults to 'qp' on all devices\n"); fprintf(stderr, " -bm Bitrate mode. Should be either 'auto', 'qp' (constant quality) or 'vbr' (variable bitrate). Optional, set to 'auto' by default which defaults to 'qp' on all devices\n");
fprintf(stderr, " except steam deck that has broken drivers and doesn't support qp.\n"); fprintf(stderr, " except steam deck that has broken drivers and doesn't support qp.\n");
@@ -2678,8 +2678,9 @@ int main(int argc, char **argv) {
} }
std::string window_str = args["-w"].value(); std::string window_str = args["-w"].value();
const bool is_portal_capture = strcmp(window_str.c_str(), "portal") == 0;
if(!restore_portal_session && strcmp(window_str.c_str(), "portal") == 0) { if(!restore_portal_session && is_portal_capture) {
fprintf(stderr, "gsr info: option '-w portal' was used without '-restore-portal-session yes'. The previous screencast session will be ignored\n"); fprintf(stderr, "gsr info: option '-w portal' was used without '-restore-portal-session yes'. The previous screencast session will be ignored\n");
} }
@@ -2704,7 +2705,7 @@ int main(int argc, char **argv) {
disable_prime_run(); disable_prime_run();
} }
if(strcmp(window_str.c_str(), "portal") == 0 && is_using_prime_run()) { if(is_portal_capture && is_using_prime_run()) {
fprintf(stderr, "Warning: use of prime-run with -w portal option is currently not supported. Disabling prime-run\n"); fprintf(stderr, "Warning: use of prime-run with -w portal option is currently not supported. Disabling prime-run\n");
disable_prime_run(); disable_prime_run();
} }
@@ -2714,7 +2715,7 @@ int main(int argc, char **argv) {
_exit(1); _exit(1);
} }
const bool is_monitor_capture = strcmp(window_str.c_str(), "focused") != 0 && strcmp(window_str.c_str(), "portal") != 0 && contains_non_hex_number(window_str.c_str()); const bool is_monitor_capture = strcmp(window_str.c_str(), "focused") != 0 && !is_portal_capture && contains_non_hex_number(window_str.c_str());
gsr_egl egl; gsr_egl egl;
if(!gsr_egl_load(&egl, dpy, wayland, is_monitor_capture)) { if(!gsr_egl_load(&egl, dpy, wayland, is_monitor_capture)) {
fprintf(stderr, "gsr error: failed to load opengl\n"); fprintf(stderr, "gsr error: failed to load opengl\n");
@@ -2771,8 +2772,8 @@ int main(int argc, char **argv) {
usage(); usage();
} }
if(framerate_mode == FramerateMode::CONTENT && wayland) { if(framerate_mode == FramerateMode::CONTENT && wayland && !is_portal_capture) {
fprintf(stderr, "Error: -fm 'content' is currently only supported on X11 and when capturing a single window.\n"); fprintf(stderr, "Error: -fm 'content' is currently only supported on X11 or when using portal capture option\n");
usage(); usage();
} }
@@ -3342,10 +3343,14 @@ int main(int argc, char **argv) {
break; break;
} }
const bool damaged = !use_damage_tracking || gsr_damage_is_damaged(&damage); bool damaged = false;
if(damaged) { if(capture->is_damaged)
damaged = capture->is_damaged(capture);
else
damaged = !use_damage_tracking || gsr_damage_is_damaged(&damage);
if(damaged)
++damage_fps_counter; ++damage_fps_counter;
}
++fps_counter; ++fps_counter;
double time_now = clock_get_monotonic_seconds(); double time_now = clock_get_monotonic_seconds();
@@ -3365,6 +3370,8 @@ int main(int argc, char **argv) {
const double num_frames_seconds = num_frames * target_fps; const double num_frames_seconds = num_frames * target_fps;
if((damaged || num_frames_seconds >= damage_timeout_seconds) && !paused/* && fps_counter < fps + 100*/) { if((damaged || num_frames_seconds >= damage_timeout_seconds) && !paused/* && fps_counter < fps + 100*/) {
gsr_damage_clear(&damage); gsr_damage_clear(&damage);
if(capture->clear_damage)
capture->clear_damage(capture);
egl.glClear(0); egl.glClear(0);
gsr_capture_capture(capture, video_frame, &color_conversion); gsr_capture_capture(capture, video_frame, &color_conversion);

View File

@@ -129,6 +129,8 @@ static void on_process_cb(void *user_data) {
self->dmabuf_data[i].offset = buffer->datas[i].chunk->offset; self->dmabuf_data[i].offset = buffer->datas[i].chunk->offset;
self->dmabuf_data[i].stride = buffer->datas[i].chunk->stride; self->dmabuf_data[i].stride = buffer->datas[i].chunk->stride;
} }
self->damaged = true;
} else { } else {
// TODO: // TODO:
} }
@@ -745,3 +747,17 @@ bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, g
pthread_mutex_unlock(&self->mutex); pthread_mutex_unlock(&self->mutex);
return true; return true;
} }
bool gsr_pipewire_is_damaged(gsr_pipewire *self) {
bool damaged = false;
pthread_mutex_lock(&self->mutex);
damaged = self->damaged;
pthread_mutex_unlock(&self->mutex);
return damaged;
}
void gsr_pipewire_clear_damage(gsr_pipewire *self) {
pthread_mutex_lock(&self->mutex);
self->damaged = false;
pthread_mutex_unlock(&self->mutex);
}