Pure vaapi capture (for capture target) and opengl composition for cursor only when capturing window and portal as well, clear background on resize for monitor capture

This commit is contained in:
dec05eba
2024-09-16 22:19:09 +02:00
parent 4bcf976a71
commit 25b7b4e84e
14 changed files with 352 additions and 144 deletions

View File

@@ -10,10 +10,10 @@ int gsr_capture_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVF
return res;
}
void gsr_capture_tick(gsr_capture *cap, AVCodecContext *video_codec_context) {
void gsr_capture_tick(gsr_capture *cap) {
assert(cap->started);
if(cap->tick)
cap->tick(cap, video_codec_context);
cap->tick(cap);
}
void gsr_capture_on_event(gsr_capture *cap, gsr_egl *egl) {
@@ -34,12 +34,6 @@ int gsr_capture_capture(gsr_capture *cap, AVFrame *frame, gsr_color_conversion *
return cap->capture(cap, frame, color_conversion);
}
void gsr_capture_capture_end(gsr_capture *cap, AVFrame *frame) {
assert(cap->started);
if(cap->capture_end)
cap->capture_end(cap, frame);
}
gsr_source_color gsr_capture_get_source_color(gsr_capture *cap) {
return cap->get_source_color(cap);
}

View File

@@ -8,7 +8,9 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <xf86drm.h>
#include <libdrm/drm_fourcc.h>
#include <libavcodec/avcodec.h>
@@ -52,6 +54,13 @@ typedef struct {
AVCodecContext *video_codec_context;
bool performance_error_shown;
int drm_fd;
uint64_t prev_sequence;
bool damaged;
vec2i prev_target_pos;
vec2i prev_plane_size;
} gsr_capture_kms;
static void gsr_capture_kms_cleanup_kms_fds(gsr_capture_kms *self) {
@@ -84,6 +93,11 @@ static void gsr_capture_kms_stop(gsr_capture_kms *self) {
self->cursor_texture_id = 0;
}
if(self->drm_fd > 0) {
close(self->drm_fd);
self->drm_fd = -1;
}
gsr_capture_kms_cleanup_kms_fds(self);
gsr_kms_client_deinit(&self->kms_client);
gsr_cursor_deinit(&self->x11_cursor);
@@ -147,6 +161,15 @@ static void monitor_callback(const gsr_monitor *monitor, void *userdata) {
fprintf(stderr, "gsr warning: reached max connector ids\n");
}
static vec2i rotate_capture_size_if_rotated(gsr_capture_kms *self, vec2i capture_size) {
if(self->monitor_rotation == GSR_MONITOR_ROT_90 || self->monitor_rotation == GSR_MONITOR_ROT_270) {
int tmp_x = capture_size.x;
capture_size.x = capture_size.y;
capture_size.y = tmp_x;
}
return capture_size;
}
static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame) {
gsr_capture_kms *self = cap->priv;
@@ -182,12 +205,10 @@ static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_c
self->capture_pos = monitor.pos;
/* Monitor size is already rotated on x11 when the monitor is rotated, no need to apply it ourselves */
if(!self->is_x11 && (self->monitor_rotation == GSR_MONITOR_ROT_90 || self->monitor_rotation == GSR_MONITOR_ROT_270)) {
self->capture_size.x = monitor.size.y;
self->capture_size.y = monitor.size.x;
} else {
if(self->is_x11)
self->capture_size = monitor.size;
}
else
self->capture_size = rotate_capture_size_if_rotated(self, monitor.size);
/* Disable vsync */
self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0);
@@ -211,6 +232,26 @@ static void gsr_capture_kms_on_event(gsr_capture *cap, gsr_egl *egl) {
gsr_cursor_on_event(&self->x11_cursor, xev);
}
static void gsr_capture_kms_tick(gsr_capture *cap) {
gsr_capture_kms *self = cap->priv;
if(self->drm_fd <= 0)
self->drm_fd = open(self->params.egl->card_path, O_RDONLY);
if(self->drm_fd <= 0)
return;
uint64_t sequence = 0;
uint64_t ns = 0;
if(drmCrtcGetSequence(self->drm_fd, 79, &sequence, &ns) != 0)
return;
if(sequence != self->prev_sequence) {
self->prev_sequence = sequence;
self->damaged = true;
}
}
static float monitor_rotation_to_radians(gsr_monitor_rotation rot) {
switch(rot) {
case GSR_MONITOR_ROT_0: return 0.0f;
@@ -386,7 +427,7 @@ 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, int target_x, int target_y, 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) {
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};
@@ -415,8 +456,8 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
break;
}
cursor_pos.x += target_x;
cursor_pos.y += target_y;
cursor_pos.x += target_pos.x;
cursor_pos.y += target_pos.y;
int fds[GSR_KMS_MAX_DMA_BUFS];
uint32_t offsets[GSR_KMS_MAX_DMA_BUFS];
@@ -444,7 +485,7 @@ 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_x, target_y, self->capture_size.x, self->capture_size.y);
self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
gsr_color_conversion_draw(color_conversion, self->cursor_texture_id,
cursor_pos, cursor_size,
@@ -454,16 +495,16 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
self->params.egl->glDisable(GL_SCISSOR_TEST);
}
static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, int target_x, int target_y) {
static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, vec2i target_pos) {
gsr_cursor_tick(&self->x11_cursor, DefaultRootWindow(self->params.egl->x11.dpy));
const vec2i cursor_pos = {
target_x + self->x11_cursor.position.x - self->x11_cursor.hotspot.x - capture_pos.x,
target_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,
target_pos.y + self->x11_cursor.position.y - self->x11_cursor.hotspot.y - capture_pos.y
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
self->params.egl->glScissor(target_x, target_y, self->capture_size.x, self->capture_size.y);
self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
gsr_color_conversion_draw(color_conversion, self->x11_cursor.texture_id,
cursor_pos, self->x11_cursor.size,
@@ -473,6 +514,14 @@ static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color
self->params.egl->glDisable(GL_SCISSOR_TEST);
}
static void gsr_capture_kms_update_capture_size_change(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i target_pos, const gsr_kms_response_item *drm_fd) {
if(target_pos.x != self->prev_target_pos.x || target_pos.y != self->prev_target_pos.y || drm_fd->src_w != self->prev_plane_size.x || drm_fd->src_h != self->prev_plane_size.y) {
self->prev_target_pos = target_pos;
self->prev_plane_size = self->capture_size;
gsr_color_conversion_clear(color_conversion);
}
}
static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_conversion *color_conversion) {
gsr_capture_kms *self = cap->priv;
@@ -494,26 +543,37 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c
bool capture_is_combined_plane = false;
const gsr_kms_response_item *drm_fd = find_monitor_drm(self, &capture_is_combined_plane);
if(!drm_fd)
if(!drm_fd) {
gsr_capture_kms_cleanup_kms_fds(self);
return -1;
}
if(drm_fd->has_hdr_metadata && self->params.hdr && hdr_metadata_is_supported_format(&drm_fd->hdr_metadata))
gsr_kms_set_hdr_metadata(self, drm_fd);
const float texture_rotation = monitor_rotation_to_radians(self->monitor_rotation);
const int target_x = max_int(0, frame->width / 2 - self->capture_size.x / 2);
const int target_y = max_int(0, frame->height / 2 - self->capture_size.y / 2);
vec2i capture_pos = self->capture_pos;
if(!capture_is_combined_plane)
capture_pos = (vec2i){drm_fd->x, drm_fd->y};
if(!self->performance_error_shown && self->monitor_rotation != GSR_MONITOR_ROT_0 && video_codec_context_is_vaapi(self->video_codec_context)) {
self->performance_error_shown = true;
fprintf(stderr,"gsr warning: gsr_capture_kms_capture: the monitor you are recording is rotated, composition will have to be used."
" 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 });
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();
}
/* Fast opengl free path */
if(self->monitor_rotation == GSR_MONITOR_ROT_0 && video_codec_context_is_vaapi(self->video_codec_context)) {
int fds[4];
@@ -526,7 +586,7 @@ 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, capture_pos.x, capture_pos.y, drm_fd->pixel_format, drm_fd->width, drm_fd->height, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs);
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);
} else {
EGLImage image = gsr_capture_kms_create_egl_image_with_fallback(self, drm_fd);
if(image) {
@@ -538,23 +598,34 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c
self->params.egl->glFinish();
gsr_color_conversion_draw(color_conversion, self->external_texture_fallback ? self->external_input_texture_id : self->input_texture_id,
(vec2i){target_x, target_y}, self->capture_size,
target_pos, self->capture_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();
}
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.
if(self->is_x11)
render_x11_cursor(self, color_conversion, capture_pos, target_x, target_y);
else if(cursor_drm_fd)
render_drm_cursor(self, color_conversion, cursor_drm_fd, target_x, target_y, texture_rotation);
if(self->is_x11) {
const vec2i cursor_monitor_offset = self->capture_pos;
render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos);
} else if(cursor_drm_fd) {
render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, texture_rotation);
}
}
self->params.egl->glFlush();
self->params.egl->glFinish();
for(int i = 0; i < 3; ++i) {
self->params.egl->glFlush();
self->params.egl->glFinish();
}
gsr_capture_kms_cleanup_kms_fds(self);
return 0;
}
@@ -566,11 +637,6 @@ static bool gsr_capture_kms_should_stop(gsr_capture *cap, bool *err) {
return false;
}
static void gsr_capture_kms_capture_end(gsr_capture *cap, AVFrame *frame) {
(void)frame;
gsr_capture_kms_cleanup_kms_fds(cap->priv);
}
static gsr_source_color gsr_capture_kms_get_source_color(gsr_capture *cap) {
(void)cap;
return GSR_SOURCE_COLOR_RGB;
@@ -607,6 +673,16 @@ static bool gsr_capture_kms_set_hdr_metadata(gsr_capture *cap, AVMasteringDispla
return true;
}
static bool gsr_capture_kms_is_damaged(gsr_capture *cap) {
gsr_capture_kms *self = cap->priv;
return self->damaged;
}
static void gsr_capture_kms_clear_damage(gsr_capture *cap) {
gsr_capture_kms *self = cap->priv;
self->damaged = false;
}
static void gsr_capture_kms_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
(void)video_codec_context;
gsr_capture_kms *self = cap->priv;
@@ -649,13 +725,14 @@ gsr_capture* gsr_capture_kms_create(const gsr_capture_kms_params *params) {
*cap = (gsr_capture) {
.start = gsr_capture_kms_start,
.on_event = gsr_capture_kms_on_event,
.tick = NULL,
.tick = gsr_capture_kms_tick,
.should_stop = gsr_capture_kms_should_stop,
.capture = gsr_capture_kms_capture,
.capture_end = gsr_capture_kms_capture_end,
.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,
.clear_damage = gsr_capture_kms_clear_damage,
.destroy = gsr_capture_kms_destroy,
.priv = cap_kms
};

View File

@@ -471,7 +471,6 @@ gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) {
.tick = NULL,
.should_stop = NULL,
.capture = gsr_capture_nvfbc_capture,
.capture_end = NULL,
.get_source_color = gsr_capture_nvfbc_get_source_color,
.uses_external_image = NULL,
.destroy = gsr_capture_nvfbc_destroy,

View File

@@ -22,18 +22,20 @@ typedef struct {
gsr_pipewire pipewire;
vec2i capture_size;
int plane_fds[GSR_PIPEWIRE_DMABUF_MAX_PLANES];
int num_plane_fds;
gsr_pipewire_dmabuf_data dmabuf_data[GSR_PIPEWIRE_DMABUF_MAX_PLANES];
int num_dmabuf_data;
AVCodecContext *video_codec_context;
} gsr_capture_portal;
static void gsr_capture_portal_cleanup_plane_fds(gsr_capture_portal *self) {
for(int i = 0; i < self->num_plane_fds; ++i) {
if(self->plane_fds[i] > 0) {
close(self->plane_fds[i]);
self->plane_fds[i] = 0;
for(int i = 0; i < self->num_dmabuf_data; ++i) {
if(self->dmabuf_data[i].fd > 0) {
close(self->dmabuf_data[i].fd);
self->dmabuf_data[i].fd = 0;
}
}
self->num_plane_fds = 0;
self->num_dmabuf_data = 0;
}
static void gsr_capture_portal_stop(gsr_capture_portal *self) {
@@ -237,7 +239,9 @@ static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
const double start_time = clock_get_monotonic_seconds();
while(clock_get_monotonic_seconds() - start_time < 5.0) {
bool uses_external_image = false;
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->plane_fds, &self->num_plane_fds, &uses_external_image)) {
uint32_t fourcc = 0;
uint64_t modifiers = 0;
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &fourcc, &modifiers, &uses_external_image)) {
gsr_capture_portal_cleanup_plane_fds(self);
self->capture_size.x = region.width;
self->capture_size.y = region.height;
@@ -300,6 +304,8 @@ static int gsr_capture_portal_start(gsr_capture *cap, AVCodecContext *video_code
frame->width = video_codec_context->width;
frame->height = video_codec_context->height;
self->video_codec_context = video_codec_context;
return 0;
}
@@ -312,39 +318,57 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
(void)color_conversion;
gsr_capture_portal *self = cap->priv;
gsr_capture_portal_cleanup_plane_fds(self);
/* TODO: Handle formats other than RGB(a) */
gsr_pipewire_region region = {0, 0, 0, 0};
gsr_pipewire_region cursor_region = {0, 0, 0, 0};
uint32_t pipewire_fourcc = 0;
uint64_t pipewire_modifiers = 0;
bool using_external_image = false;
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->plane_fds, &self->num_plane_fds, &using_external_image)) {
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &pipewire_fourcc, &pipewire_modifiers, &using_external_image)) {
if(region.width != self->capture_size.x || region.height != self->capture_size.y) {
gsr_color_conversion_clear(color_conversion);
self->capture_size.x = region.width;
self->capture_size.y = region.height;
gsr_color_conversion_clear(color_conversion);
}
} else {
return 0;
}
self->params.egl->glFlush();
self->params.egl->glFinish();
const int target_x = max_int(0, frame->width / 2 - self->capture_size.x / 2);
const int target_y = max_int(0, frame->height / 2 - self->capture_size.y / 2);
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) };
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
(vec2i){target_x, target_y}, self->capture_size,
(vec2i){region.x, region.y}, self->capture_size,
0.0f, using_external_image);
// TODO: Handle region crop
/* Fast opengl free path */
if(video_codec_context_is_vaapi(self->video_codec_context)) {
int fds[4];
uint32_t offsets[4];
uint32_t pitches[4];
uint64_t modifiers[4];
for(int i = 0; i < self->num_dmabuf_data; ++i) {
fds[i] = self->dmabuf_data[i].fd;
offsets[i] = self->dmabuf_data[i].offset;
pitches[i] = self->dmabuf_data[i].stride;
modifiers[i] = pipewire_modifiers;
}
vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){region.x, region.y}, self->capture_size, target_pos, self->capture_size, pipewire_fourcc, self->capture_size, fds, offsets, pitches, modifiers, self->num_dmabuf_data);
} else {
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
target_pos, self->capture_size,
(vec2i){region.x, region.y}, self->capture_size,
0.0f, using_external_image);
}
if(self->params.record_cursor) {
const vec2i cursor_pos = {
target_x + cursor_region.x,
target_y + cursor_region.y
target_pos.x + cursor_region.x,
target_pos.y + cursor_region.y
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
self->params.egl->glScissor(target_x, target_y, self->capture_size.x, self->capture_size.y);
self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){cursor_region.width, cursor_region.height},
(vec2i){0, 0}, (vec2i){cursor_region.width, cursor_region.height},
@@ -355,13 +379,9 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
self->params.egl->glFlush();
self->params.egl->glFinish();
return 0;
}
static void gsr_capture_portal_capture_end(gsr_capture *cap, AVFrame *frame) {
(void)frame;
gsr_capture_portal *self = cap->priv;
gsr_capture_portal_cleanup_plane_fds(self);
return 0;
}
static gsr_source_color gsr_capture_portal_get_source_color(gsr_capture *cap) {
@@ -418,7 +438,6 @@ gsr_capture* gsr_capture_portal_create(const gsr_capture_portal_params *params)
.tick = NULL,
.should_stop = NULL,
.capture = gsr_capture_portal_capture,
.capture_end = gsr_capture_portal_capture_end,
.get_source_color = gsr_capture_portal_get_source_color,
.uses_external_image = gsr_capture_portal_uses_external_image,
.is_damaged = gsr_capture_portal_is_damaged,

View File

@@ -29,6 +29,7 @@ typedef struct {
double window_resize_timer;
WindowTexture window_texture;
AVCodecContext *video_codec_context;
Atom net_active_window_atom;
@@ -122,12 +123,12 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_
frame->width = video_codec_context->width;
frame->height = video_codec_context->height;
self->video_codec_context = video_codec_context;
self->window_resize_timer = clock_get_monotonic_seconds();
return 0;
}
static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_codec_context) {
(void)video_codec_context;
static void gsr_capture_xcomposite_tick(gsr_capture *cap) {
gsr_capture_xcomposite *self = cap->priv;
if(self->params.follow_focused && !self->follow_focused_initialized) {
@@ -255,27 +256,31 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame, gsr_
gsr_color_conversion_clear(color_conversion);
}
const int target_x = max_int(0, frame->width / 2 - self->texture_size.x / 2);
const int target_y = max_int(0, frame->height / 2 - self->texture_size.y / 2);
const vec2i target_pos = { max_int(0, frame->width / 2 - self->texture_size.x / 2), max_int(0, frame->height / 2 - self->texture_size.y / 2) };
self->params.egl->glFlush();
self->params.egl->glFinish();
gsr_color_conversion_draw(color_conversion, window_texture_get_opengl_texture_id(&self->window_texture),
(vec2i){target_x, target_y}, self->texture_size,
(vec2i){0, 0}, self->texture_size,
0.0f, false);
/* Fast opengl free path */
if(video_codec_context_is_vaapi(self->video_codec_context)) {
vaapi_copy_egl_image_to_video_surface(self->params.egl, self->window_texture.image, (vec2i){0, 0}, self->texture_size, target_pos, self->texture_size, self->video_codec_context, frame);
} else {
gsr_color_conversion_draw(color_conversion, window_texture_get_opengl_texture_id(&self->window_texture),
target_pos, self->texture_size,
(vec2i){0, 0}, self->texture_size,
0.0f, false);
}
if(self->params.record_cursor && self->cursor.visible) {
gsr_cursor_tick(&self->cursor, self->window);
const vec2i cursor_pos = {
target_x + self->cursor.position.x - self->cursor.hotspot.x,
target_y + self->cursor.position.y - self->cursor.hotspot.y
target_pos.x + self->cursor.position.x - self->cursor.hotspot.x,
target_pos.y + self->cursor.position.y - self->cursor.hotspot.y
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
self->params.egl->glScissor(target_x, target_y, self->texture_size.x, self->texture_size.y);
self->params.egl->glScissor(target_pos.x, target_pos.y, self->texture_size.x, self->texture_size.y);
gsr_color_conversion_draw(color_conversion, self->cursor.texture_id,
cursor_pos, self->cursor.size,
@@ -335,7 +340,6 @@ gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *
.tick = gsr_capture_xcomposite_tick,
.should_stop = gsr_capture_xcomposite_should_stop,
.capture = gsr_capture_xcomposite_capture,
.capture_end = NULL,
.get_source_color = gsr_capture_xcomposite_get_source_color,
.uses_external_image = NULL,
.get_window_id = gsr_capture_xcomposite_get_window_id,