aboutsummaryrefslogtreecommitdiff
path: root/src/capture/kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/capture/kms.c')
-rw-r--r--src/capture/kms.c106
1 files changed, 60 insertions, 46 deletions
diff --git a/src/capture/kms.c b/src/capture/kms.c
index 030d609..c85811e 100644
--- a/src/capture/kms.c
+++ b/src/capture/kms.c
@@ -54,6 +54,7 @@ typedef struct {
AVCodecContext *video_codec_context;
bool performance_error_shown;
+ bool fast_path_failed;
//int drm_fd;
//uint64_t prev_sequence;
@@ -213,8 +214,15 @@ static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_c
/* Disable vsync */
self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0);
- video_codec_context->width = FFALIGN(self->capture_size.x, 2);
- video_codec_context->height = FFALIGN(self->capture_size.y, 2);
+ if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) {
+ self->params.output_resolution = self->capture_size;
+ video_codec_context->width = FFALIGN(self->capture_size.x, 2);
+ video_codec_context->height = FFALIGN(self->capture_size.y, 2);
+ } else {
+ self->params.output_resolution = scale_keep_aspect_ratio(self->capture_size, self->params.output_resolution);
+ video_codec_context->width = FFALIGN(self->params.output_resolution.x, 2);
+ video_codec_context->height = FFALIGN(self->params.output_resolution.y, 2);
+ }
frame->width = video_codec_context->width;
frame->height = video_codec_context->height;
@@ -232,7 +240,7 @@ static void gsr_capture_kms_on_event(gsr_capture *cap, gsr_egl *egl) {
gsr_cursor_on_event(&self->x11_cursor, xev);
}
-// TODO: This is disabled for now because we want to be able to record at a framerate highe than the monitor framerate
+// TODO: This is disabled for now because we want to be able to record at a framerate higher than the monitor framerate
// static void gsr_capture_kms_tick(gsr_capture *cap) {
// gsr_capture_kms *self = cap->priv;
@@ -428,7 +436,12 @@ static gsr_kms_response_item* find_cursor_drm_if_on_monitor(gsr_capture_kms *sel
return cursor_drm_fd;
}
-static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, float texture_rotation) {
+static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, float texture_rotation, vec2i output_size) {
+ const vec2d scale = {
+ self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
+ self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
+ };
+
const bool cursor_texture_id_is_external = self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA;
const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
@@ -457,6 +470,9 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
break;
}
+ cursor_pos.x *= scale.x;
+ cursor_pos.y *= scale.y;
+
cursor_pos.x += target_pos.x;
cursor_pos.y += target_pos.y;
@@ -486,34 +502,39 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
self->params.egl->eglDestroyImage(self->params.egl->egl_display, cursor_image);
self->params.egl->glEnable(GL_SCISSOR_TEST);
- self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
+ self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
gsr_color_conversion_draw(color_conversion, self->cursor_texture_id,
- cursor_pos, cursor_size,
+ cursor_pos, (vec2i){cursor_size.x * scale.x, cursor_size.y * scale.y},
(vec2i){0, 0}, cursor_size,
- texture_rotation, cursor_texture_id_is_external);
+ texture_rotation, cursor_texture_id_is_external, GSR_SOURCE_COLOR_RGB);
self->params.egl->glDisable(GL_SCISSOR_TEST);
}
-static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, vec2i target_pos) {
+static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, vec2i target_pos, vec2i output_size) {
if(!self->x11_cursor.visible)
return;
+ const vec2d scale = {
+ self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
+ self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
+ };
+
gsr_cursor_tick(&self->x11_cursor, DefaultRootWindow(self->params.egl->x11.dpy));
const vec2i cursor_pos = {
- target_pos.x + self->x11_cursor.position.x - self->x11_cursor.hotspot.x - capture_pos.x,
- target_pos.y + self->x11_cursor.position.y - self->x11_cursor.hotspot.y - capture_pos.y
+ target_pos.x + (self->x11_cursor.position.x - self->x11_cursor.hotspot.x - capture_pos.x) * scale.x,
+ target_pos.y + (self->x11_cursor.position.y - self->x11_cursor.hotspot.y - capture_pos.y) * scale.y
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
- self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
+ self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
gsr_color_conversion_draw(color_conversion, self->x11_cursor.texture_id,
- cursor_pos, self->x11_cursor.size,
+ cursor_pos, (vec2i){self->x11_cursor.size.x * scale.x, self->x11_cursor.size.y * scale.y},
(vec2i){0, 0}, self->x11_cursor.size,
- 0.0f, false);
+ 0.0f, false, GSR_SOURCE_COLOR_RGB);
self->params.egl->glDisable(GL_SCISSOR_TEST);
}
@@ -561,25 +582,25 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c
" If you are experience performance problems in the video then record a single window on X11 or use portal capture option instead\n");
}
- const float texture_rotation = monitor_rotation_to_radians(self->monitor_rotation);
- const vec2i target_pos = { max_int(0, frame->width / 2 - self->capture_size.x / 2), max_int(0, frame->height / 2 - self->capture_size.y / 2) };
self->capture_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->src_w, drm_fd->src_h });
+
+ const bool is_scaled = self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0;
+ vec2i output_size = is_scaled ? self->params.output_resolution : self->capture_size;
+ output_size = scale_keep_aspect_ratio(self->capture_size, output_size);
+
+ const float texture_rotation = monitor_rotation_to_radians(self->monitor_rotation);
+ const vec2i target_pos = { max_int(0, frame->width / 2 - output_size.x / 2), max_int(0, frame->height / 2 - output_size.y / 2) };
gsr_capture_kms_update_capture_size_change(self, color_conversion, target_pos, drm_fd);
vec2i capture_pos = self->capture_pos;
if(!capture_is_combined_plane)
capture_pos = (vec2i){drm_fd->x, drm_fd->y};
- // TODO: Hack!! cursor flickers without this when using vaapi copy on wayland.
- // There is probably some sync issue between opengl and vaapi.
- // Remove this when that has been figured out. Same for the below glFlush && glFinish
- for(int i = 0; i < 3; ++i) {
- self->params.egl->glFlush();
- self->params.egl->glFinish();
- }
+ self->params.egl->glFlush();
+ self->params.egl->glFinish();
/* Fast opengl free path */
- if(self->monitor_rotation == GSR_MONITOR_ROT_0 && video_codec_context_is_vaapi(self->video_codec_context) && self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD) {
+ if(!self->fast_path_failed && self->monitor_rotation == GSR_MONITOR_ROT_0 && video_codec_context_is_vaapi(self->video_codec_context) && self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD) {
int fds[4];
uint32_t offsets[4];
uint32_t pitches[4];
@@ -590,44 +611,43 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c
pitches[i] = drm_fd->dma_buf[i].pitch;
modifiers[i] = drm_fd->modifier;
}
- vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){capture_pos.x, capture_pos.y}, self->capture_size, target_pos, self->capture_size, drm_fd->pixel_format, (vec2i){drm_fd->width, drm_fd->height}, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs);
+ if(!vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){capture_pos.x, capture_pos.y}, self->capture_size, target_pos, output_size, drm_fd->pixel_format, (vec2i){drm_fd->width, drm_fd->height}, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs)) {
+ fprintf(stderr, "gsr error: gsr_capture_kms_capture: vaapi_copy_drm_planes_to_video_surface failed, falling back to opengl copy. Please report this as an issue at https://github.com/dec05eba/gpu-screen-recorder-issues\n");
+ self->fast_path_failed = true;
+ }
} else {
+ self->fast_path_failed = true;
+ }
+
+ if(self->fast_path_failed) {
EGLImage image = gsr_capture_kms_create_egl_image_with_fallback(self, drm_fd);
if(image) {
gsr_capture_kms_bind_image_to_input_texture_with_fallback(self, image);
self->params.egl->eglDestroyImage(self->params.egl->egl_display, image);
}
- self->params.egl->glFlush();
- self->params.egl->glFinish();
-
gsr_color_conversion_draw(color_conversion, self->external_texture_fallback ? self->external_input_texture_id : self->input_texture_id,
- target_pos, self->capture_size,
+ target_pos, output_size,
capture_pos, self->capture_size,
- texture_rotation, self->external_texture_fallback);
- }
-
- for(int i = 0; i < 3; ++i) {
- self->params.egl->glFlush();
- self->params.egl->glFinish();
+ texture_rotation, self->external_texture_fallback, GSR_SOURCE_COLOR_RGB);
}
if(self->params.record_cursor) {
gsr_kms_response_item *cursor_drm_fd = find_cursor_drm_if_on_monitor(self, drm_fd->connector_id, capture_is_combined_plane);
// The cursor is handled by x11 on x11 instead of using the cursor drm plane because on prime systems with a dedicated nvidia gpu
// the cursor plane is not available when the cursor is on the monitor controlled by the nvidia device.
+ // TODO: This doesn't work properly with software cursor on x11 since it will draw the x11 cursor on top of the cursor already in the framebuffer.
+ // Detect if software cursor is used on x11 somehow.
if(self->is_x11) {
const vec2i cursor_monitor_offset = self->capture_pos;
- render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos);
+ render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos, output_size);
} else if(cursor_drm_fd) {
- render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, texture_rotation);
+ render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, texture_rotation, output_size);
}
}
- for(int i = 0; i < 3; ++i) {
- self->params.egl->glFlush();
- self->params.egl->glFinish();
- }
+ self->params.egl->glFlush();
+ self->params.egl->glFinish();
gsr_capture_kms_cleanup_kms_fds(self);
@@ -641,11 +661,6 @@ static bool gsr_capture_kms_should_stop(gsr_capture *cap, bool *err) {
return false;
}
-static gsr_source_color gsr_capture_kms_get_source_color(gsr_capture *cap) {
- (void)cap;
- return GSR_SOURCE_COLOR_RGB;
-}
-
static bool gsr_capture_kms_uses_external_image(gsr_capture *cap) {
(void)cap;
return true;
@@ -732,7 +747,6 @@ gsr_capture* gsr_capture_kms_create(const gsr_capture_kms_params *params) {
//.tick = gsr_capture_kms_tick,
.should_stop = gsr_capture_kms_should_stop,
.capture = gsr_capture_kms_capture,
- .get_source_color = gsr_capture_kms_get_source_color,
.uses_external_image = gsr_capture_kms_uses_external_image,
.set_hdr_metadata = gsr_capture_kms_set_hdr_metadata,
//.is_damaged = gsr_capture_kms_is_damaged,