From 22a0a01553debd549e1f1f0058bc516cec28196b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 22 Jul 2023 02:57:38 +0200 Subject: AMD/Intel capture cursor --- TODO | 4 +- include/capture/kms_vaapi.h | 1 - kms/kms_shared.h | 5 + kms/server/kms_server.c | 107 +++++++++++++++----- src/capture/kms_cuda.c | 4 +- src/capture/kms_vaapi.c | 237 ++++++++++++-------------------------------- src/main.cpp | 4 +- 7 files changed, 158 insertions(+), 204 deletions(-) diff --git a/TODO b/TODO index 3cb9e6a..286f2ed 100644 --- a/TODO +++ b/TODO @@ -79,9 +79,7 @@ Test kms_cuda on hyprland and other wlroots based compositor to see if it works. Support "screen" (all monitors) capture on wayland. This should be done by getting all drm fds and multiple EGL_DMA_BUF_PLANEX_FD_EXT to create one egl image with all fds combined. Support pipewire screen capture? -Support screen rotation in amd/intel/nvidia wayland. -Capture cursor on amd/intel wayland without xwayland. +Support screen rotation. When nvidia supports hardware cursor then capture the cursor. Right now the cursor is captured because it's a software cursor so it's composed on the dma buf. CPU usage is pretty high on AMD/Intel/(Nvidia(wayland)), why? opening and closing fds, creating egl, cuda association, is slow when done every frame. Test if desktop portal screencast has better performance. -Cursor on amd/intel wayland only shows up when the cursor is above xwayland applications. diff --git a/include/capture/kms_vaapi.h b/include/capture/kms_vaapi.h index 8e11682..77b292a 100644 --- a/include/capture/kms_vaapi.h +++ b/include/capture/kms_vaapi.h @@ -9,7 +9,6 @@ typedef struct _XDisplay Display; typedef struct { gsr_egl *egl; - Display *dpy; const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */ gsr_gpu_info gpu_inf; const char *card_path; /* reference */ diff --git a/kms/kms_shared.h b/kms/kms_shared.h index e0687b2..616af43 100644 --- a/kms/kms_shared.h +++ b/kms/kms_shared.h @@ -31,6 +31,11 @@ typedef struct { uint64_t modifier; uint32_t connector_id; /* 0 if unknown */ bool is_combined_plane; + bool is_cursor; + int x; + int y; + int src_w; + int src_h; } gsr_kms_response_fd; typedef struct { diff --git a/kms/server/kms_server.c b/kms/server/kms_server.c index 4ed11fa..33f5dd4 100644 --- a/kms/server/kms_server.c +++ b/kms/server/kms_server.c @@ -85,7 +85,28 @@ static bool connector_get_property_by_name(int drmfd, drmModeConnectorPtr props, return false; } -static bool plane_is_cursor_plane(int drmfd, uint32_t plane_id) { +typedef enum { + PLANE_PROPERTY_X = 1 << 0, + PLANE_PROPERTY_Y = 1 << 1, + PLANE_PROPERTY_SRC_X = 1 << 2, + PLANE_PROPERTY_SRC_Y = 1 << 3, + PLANE_PROPERTY_SRC_W = 1 << 4, + PLANE_PROPERTY_SRC_H = 1 << 5, + PLANE_PROPERTY_IS_CURSOR = 1 << 6, +} plane_property_mask; + +/* Returns plane_property_mask */ +static uint32_t plane_get_properties(int drmfd, uint32_t plane_id, bool *is_cursor, int *x, int *y, int *src_x, int *src_y, int *src_w, int *src_h) { + *is_cursor = false; + *x = 0; + *y = 0; + *src_x = 0; + *src_y = 0; + *src_w = 0; + *src_h = 0; + + plane_property_mask property_mask = 0; + drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drmfd, plane_id, DRM_MODE_OBJECT_PLANE); if(!props) return false; @@ -95,26 +116,42 @@ static bool plane_is_cursor_plane(int drmfd, uint32_t plane_id) { if(!prop) continue; + // SRC_* values are fixed 16.16 points const uint32_t type = prop->flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); - if((type & DRM_MODE_PROP_ENUM) && strcmp(prop->name, "type") == 0) { + if((type & DRM_MODE_PROP_SIGNED_RANGE) && strcmp(prop->name, "CRTC_X") == 0) { + *x = (int)props->prop_values[i]; + property_mask |= PLANE_PROPERTY_X; + } else if((type & DRM_MODE_PROP_SIGNED_RANGE) && strcmp(prop->name, "CRTC_Y") == 0) { + *y = (int)props->prop_values[i]; + property_mask |= PLANE_PROPERTY_Y; + } else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_X") == 0) { + *src_x = (int)(props->prop_values[i] >> 16); + property_mask |= PLANE_PROPERTY_SRC_X; + } else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_Y") == 0) { + *src_y = (int)(props->prop_values[i] >> 16); + property_mask |= PLANE_PROPERTY_SRC_Y; + } else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_W") == 0) { + *src_w = (int)(props->prop_values[i] >> 16); + property_mask |= PLANE_PROPERTY_SRC_W; + } else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_H") == 0) { + *src_h = (int)(props->prop_values[i] >> 16); + property_mask |= PLANE_PROPERTY_SRC_H; + } else if((type & DRM_MODE_PROP_ENUM) && strcmp(prop->name, "type") == 0) { const uint64_t current_enum_value = props->prop_values[i]; - bool is_cursor = false; - for(int j = 0; j < prop->count_enums; ++j) { if(prop->enums[j].value == current_enum_value && strcmp(prop->enums[j].name, "Cursor") == 0) { - is_cursor = true; + *is_cursor = true; + property_mask |= PLANE_PROPERTY_IS_CURSOR; break; } } - - drmModeFreeProperty(prop); - return is_cursor; } + drmModeFreeProperty(prop); } drmModeFreeObjectProperties(props); - return false; + return property_mask; } /* Returns 0 if not found */ @@ -175,22 +212,27 @@ static int kms_get_plane_ids(gsr_drm *drm) { continue; } - if(!plane->fb_id) - goto next; - - if(plane_is_cursor_plane(drm->drmfd, plane->plane_id)) - goto next; - - // TODO: Fallback to getfb(1)? - drmfb = drmModeGetFB2(drm->drmfd, plane->fb_id); - if(drmfb) { - drm->plane_ids[drm->num_plane_ids] = plane->plane_id; - drm->connector_ids[drm->num_plane_ids] = get_connector_by_crtc_id(&c2crtc_map, plane->crtc_id); - ++drm->num_plane_ids; - drmModeFreeFB2(drmfb); + if(plane->fb_id) { + // TODO: Fallback to getfb(1)? + drmfb = drmModeGetFB2(drm->drmfd, plane->fb_id); + if(drmfb) { + drm->plane_ids[drm->num_plane_ids] = plane->plane_id; + drm->connector_ids[drm->num_plane_ids] = get_connector_by_crtc_id(&c2crtc_map, plane->crtc_id); + ++drm->num_plane_ids; + if(drmfb) + drmModeFreeFB2(drmfb); + } + } else { + bool is_cursor = false; + int x = 0, y = 0, src_x = 0, src_y = 0, src_w = 0, src_h = 0; + plane_get_properties(drm->drmfd, plane->plane_id, &is_cursor, &x, &y, &src_x, &src_y, &src_w, &src_h); + if(is_cursor) { + drm->plane_ids[drm->num_plane_ids] = plane->plane_id; + drm->connector_ids[drm->num_plane_ids] = 0; + ++drm->num_plane_ids; + } } - next: drmModeFreePlane(plane); } @@ -230,6 +272,9 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) { goto next; } + if(!plane->fb_id) + goto next; + drmfb = drmModeGetFB2(drm->drmfd, plane->fb_id); if(!drmfb) { // Commented out for now because we get here if the cursor is moved to another monitor and we dont care about the cursor @@ -258,6 +303,10 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) { continue; } + bool is_cursor = false; + int x = 0, y = 0, src_x = 0, src_y = 0, src_w = 0, src_h = 0; + plane_get_properties(drm->drmfd, plane->plane_id, &is_cursor, &x, &y, &src_x, &src_y, &src_w, &src_h); + response->fds[response->num_fds].fd = fb_fd; response->fds[response->num_fds].width = drmfb->width; response->fds[response->num_fds].height = drmfb->height; @@ -267,6 +316,18 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) { response->fds[response->num_fds].modifier = drmfb->modifier; response->fds[response->num_fds].connector_id = drm->connector_ids[i]; response->fds[response->num_fds].is_combined_plane = drmfb_has_multiple_handles(drmfb); + response->fds[response->num_fds].is_cursor = is_cursor; + if(response->fds[response->num_fds].is_cursor) { + response->fds[response->num_fds].x = x; + response->fds[response->num_fds].y = y; + response->fds[response->num_fds].src_w = 0; + response->fds[response->num_fds].src_h = 0; + } else { + response->fds[response->num_fds].x = src_x; + response->fds[response->num_fds].y = src_y; + response->fds[response->num_fds].src_w = src_w; + response->fds[response->num_fds].src_h = src_h; + } ++response->num_fds; next: diff --git a/src/capture/kms_cuda.c b/src/capture/kms_cuda.c index c1d272e..c6b207f 100644 --- a/src/capture/kms_cuda.c +++ b/src/capture/kms_cuda.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -260,7 +258,7 @@ static gsr_kms_response_fd* find_largest_drm(gsr_kms_response *kms_response) { gsr_kms_response_fd *largest_drm = &kms_response->fds[0]; for(int i = 0; i < kms_response->num_fds; ++i) { const int64_t size = (int64_t)kms_response->fds[i].width * (int64_t)kms_response->fds[i].height; - if(size > largest_size) { + if(size > largest_size && !kms_response->fds[i].is_cursor) { largest_size = size; largest_drm = &kms_response->fds[i]; } diff --git a/src/capture/kms_vaapi.c b/src/capture/kms_vaapi.c index 75bd378..2c5101c 100644 --- a/src/capture/kms_vaapi.c +++ b/src/capture/kms_vaapi.c @@ -2,13 +2,10 @@ #include "../../kms/client/kms_client.h" #include "../../include/utils.h" #include "../../include/color_conversion.h" -#include "../../include/cursor.h" #include #include #include #include -#include -#include #include #include #include @@ -23,13 +20,6 @@ typedef struct { int num_connector_ids; } MonitorId; -typedef enum { - X11_ROT_0 = 1 << 0, - X11_ROT_90 = 1 << 1, - X11_ROT_180 = 1 << 2, - X11_ROT_270 = 1 << 3 -} X11Rotation; - typedef struct { gsr_capture_kms_vaapi_params params; XEvent xev; @@ -43,25 +33,19 @@ typedef struct { gsr_kms_response_fd wayland_kms_data; bool using_wayland_capture; - vec2i screen_size; vec2i capture_pos; vec2i capture_size; - bool screen_capture; MonitorId monitor_id; VADisplay va_dpy; - bool requires_rotation; - X11Rotation x11_rot; - VADRMPRIMESurfaceDescriptor prime; unsigned int input_texture; unsigned int target_textures[2]; + unsigned int cursor_texture; gsr_color_conversion color_conversion; - - gsr_cursor cursor; } gsr_capture_kms_vaapi; static int max_int(int a, int b) { @@ -123,22 +107,11 @@ static bool drm_create_codec_context(gsr_capture_kms_vaapi *cap_kms, AVCodecCont typedef struct { gsr_capture_kms_vaapi *cap_kms; - Atom randr_connector_id_atom; const char *monitor_to_capture; int monitor_to_capture_len; int num_monitors; - int rotation; - bool wayland; } MonitorCallbackUserdata; -static bool properties_has_atom(Atom *props, int nprop, Atom atom) { - for(int i = 0; i < nprop; ++i) { - if(props[i] == atom) - return true; - } - return false; -} - static void monitor_callback(const gsr_monitor *monitor, void *userdata) { (void)monitor; MonitorCallbackUserdata *monitor_callback_userdata = userdata; @@ -147,44 +120,9 @@ static void monitor_callback(const gsr_monitor *monitor, void *userdata) { if(monitor_callback_userdata->monitor_to_capture_len != monitor->name_len || memcmp(monitor_callback_userdata->monitor_to_capture, monitor->name, monitor->name_len) != 0) return; - if(monitor_callback_userdata->wayland) { - if(monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids < MAX_CONNECTOR_IDS) { - monitor_callback_userdata->cap_kms->monitor_id.connector_ids[monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids] = monitor->connector_id; - ++monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids; - } - } else { - if(strcmp(monitor_callback_userdata->monitor_to_capture, "screen") == 0) - monitor_callback_userdata->rotation = monitor->crt_info->rotation; - - monitor_callback_userdata->rotation = monitor->crt_info->rotation; - for(int i = 0; i < monitor->crt_info->noutput && monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids < MAX_CONNECTOR_IDS; ++i) { - int nprop = 0; - Atom *props = XRRListOutputProperties(monitor_callback_userdata->cap_kms->params.dpy, monitor->crt_info->outputs[i], &nprop); - if(!props) - continue; - - if(!properties_has_atom(props, nprop, monitor_callback_userdata->randr_connector_id_atom)) { - XFree(props); - continue; - } - - Atom type = 0; - int format = 0; - unsigned long bytes_after = 0; - unsigned long nitems = 0; - unsigned char *prop = NULL; - XRRGetOutputProperty(monitor_callback_userdata->cap_kms->params.dpy, monitor->crt_info->outputs[i], - monitor_callback_userdata->randr_connector_id_atom, - 0, 128, false, false, AnyPropertyType, - &type, &format, &nitems, &bytes_after, &prop); - - if(type == XA_INTEGER && format == 32) { - monitor_callback_userdata->cap_kms->monitor_id.connector_ids[monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids] = *(long*)prop; - ++monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids; - } - - XFree(props); - } + if(monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids < MAX_CONNECTOR_IDS) { + monitor_callback_userdata->cap_kms->monitor_id.connector_ids[monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids] = monitor->connector_id; + ++monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids; } if(monitor_callback_userdata->cap_kms->monitor_id.num_connector_ids == MAX_CONNECTOR_IDS) @@ -194,8 +132,6 @@ static void monitor_callback(const gsr_monitor *monitor, void *userdata) { static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_codec_context) { gsr_capture_kms_vaapi *cap_kms = cap->priv; - cap_kms->x11_rot = X11_ROT_0; - gsr_monitor monitor; cap_kms->monitor_id.num_connector_ids = 0; if(gsr_egl_start_capture(cap_kms->params.egl, cap_kms->params.display_to_capture)) { @@ -211,54 +147,20 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c return -1; } - void *connection = cap_kms->params.wayland ? (void*)cap_kms->params.card_path : (void*)cap_kms->params.dpy; - const gsr_connection_type connection_type = cap_kms->params.wayland ? GSR_CONNECTION_DRM : GSR_CONNECTION_X11; - MonitorCallbackUserdata monitor_callback_userdata = { - cap_kms, None, + cap_kms, cap_kms->params.display_to_capture, strlen(cap_kms->params.display_to_capture), 0, - X11_ROT_0, - true }; - - if(cap_kms->params.wayland) { - for_each_active_monitor_output(connection, connection_type, monitor_callback, &monitor_callback_userdata); - - cap_kms->screen_size.x = 0; - cap_kms->screen_size.y = 0; - } else { - const Atom randr_connector_id_atom = XInternAtom(cap_kms->params.dpy, "CONNECTOR_ID", False); - monitor_callback_userdata.randr_connector_id_atom = randr_connector_id_atom; - monitor_callback_userdata.wayland = false; - for_each_active_monitor_output(connection, connection_type, monitor_callback, &monitor_callback_userdata); - - cap_kms->screen_size.x = WidthOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy)); - cap_kms->screen_size.y = HeightOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy)); - } + + for_each_active_monitor_output((void*)cap_kms->params.card_path, GSR_CONNECTION_DRM, monitor_callback, &monitor_callback_userdata); gsr_monitor monitor; - if(strcmp(cap_kms->params.display_to_capture, "screen") == 0) { - monitor.pos.x = 0; - monitor.pos.y = 0; - monitor.size = cap_kms->screen_size; - cap_kms->screen_capture = true; - } else if(!get_monitor_by_name(connection, connection_type, cap_kms->params.display_to_capture, &monitor)) { + if(!get_monitor_by_name((void*)cap_kms->params.card_path, GSR_CONNECTION_DRM, cap_kms->params.display_to_capture, &monitor)) { fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to find monitor by name \"%s\"\n", cap_kms->params.display_to_capture); gsr_capture_kms_vaapi_stop(cap, video_codec_context); return -1; } - - // TODO: Find a better way to do this. Is this info available somewhere in drm? it should be! - - // Note: workaround AMD/Intel issue. If there is one monitor enabled and it's rotated then - // the drm buf will also be rotated. This only happens when you only have one monitor enabled. - cap_kms->x11_rot = monitor_callback_userdata.rotation; - if(monitor_callback_userdata.num_monitors == 1 && cap_kms->x11_rot != X11_ROT_0) { - cap_kms->requires_rotation = true; - } else { - cap_kms->requires_rotation = false; - } } cap_kms->capture_pos = monitor.pos; @@ -275,16 +177,6 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c return -1; } - if(cap_kms->params.dpy && !cap_kms->params.wayland) { - if(gsr_cursor_init(&cap_kms->cursor, cap_kms->params.egl, cap_kms->params.dpy) != 0) { - gsr_capture_kms_vaapi_stop(cap, video_codec_context); - return -1; - } - - gsr_cursor_change_window_target(&cap_kms->cursor, DefaultRootWindow(cap_kms->params.dpy)); - gsr_cursor_update(&cap_kms->cursor, &cap_kms->xev); - } - return 0; } @@ -300,13 +192,6 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c // TODO: cap_kms->params.egl->glClear(GL_COLOR_BUFFER_BIT); - if(cap_kms->params.dpy && !cap_kms->params.wayland) { - while(XPending(cap_kms->params.dpy)) { - XNextEvent(cap_kms->params.dpy, &cap_kms->xev); - gsr_cursor_update(&cap_kms->cursor, &cap_kms->xev); - } - } - if(!cap_kms->created_hw_frame) { cap_kms->created_hw_frame = true; @@ -354,6 +239,14 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c cap_kms->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0); + cap_kms->params.egl->glGenTextures(1, &cap_kms->cursor_texture); + cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, cap_kms->cursor_texture); + cap_kms->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + cap_kms->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + cap_kms->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + cap_kms->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0); + if(cap_kms->prime.fourcc == FOURCC_NV12) { cap_kms->params.egl->glGenTextures(2, cap_kms->target_textures); for(int i = 0; i < 2; ++i) { @@ -470,7 +363,7 @@ static gsr_kms_response_fd* find_largest_drm(gsr_kms_response *kms_response) { gsr_kms_response_fd *largest_drm = &kms_response->fds[0]; for(int i = 0; i < kms_response->num_fds; ++i) { const int64_t size = (int64_t)kms_response->fds[i].width * (int64_t)kms_response->fds[i].height; - if(size > largest_size) { + if(size > largest_size && !kms_response->fds[i].is_cursor) { largest_size = size; largest_drm = &kms_response->fds[i]; } @@ -478,6 +371,14 @@ static gsr_kms_response_fd* find_largest_drm(gsr_kms_response *kms_response) { return largest_drm; } +static gsr_kms_response_fd* find_cursor_drm(gsr_kms_response *kms_response) { + for(int i = 0; i < kms_response->num_fds; ++i) { + if(kms_response->fds[i].is_cursor) + return &kms_response->fds[i]; + } + return NULL; +} + static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { (void)frame; gsr_capture_kms_vaapi *cap_kms = cap->priv; @@ -490,7 +391,7 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { cap_kms->kms_response.num_fds = 0; gsr_kms_response_fd *drm_fd = NULL; - bool requires_rotation = cap_kms->requires_rotation; + gsr_kms_response_fd *cursor_drm_fd = NULL; if(cap_kms->using_wayland_capture) { gsr_egl_update(cap_kms->params.egl); cap_kms->wayland_kms_data.fd = cap_kms->params.egl->fd; @@ -522,31 +423,25 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { return -1; } - if(cap_kms->screen_capture) { + for(int i = 0; i < cap_kms->monitor_id.num_connector_ids; ++i) { + drm_fd = find_drm_by_connector_id(&cap_kms->kms_response, cap_kms->monitor_id.connector_ids[i]); + if(drm_fd) + break; + } + + if(!drm_fd) { drm_fd = find_first_combined_drm(&cap_kms->kms_response); if(!drm_fd) drm_fd = find_largest_drm(&cap_kms->kms_response); - } else { - for(int i = 0; i < cap_kms->monitor_id.num_connector_ids; ++i) { - drm_fd = find_drm_by_connector_id(&cap_kms->kms_response, cap_kms->monitor_id.connector_ids[i]); - if(drm_fd) { - requires_rotation = cap_kms->x11_rot != X11_ROT_0; - break; - } - } - - if(!drm_fd) { - drm_fd = find_first_combined_drm(&cap_kms->kms_response); - if(!drm_fd) - drm_fd = find_largest_drm(&cap_kms->kms_response); - } } + + cursor_drm_fd = find_cursor_drm(&cap_kms->kms_response); } if(!drm_fd) return -1; - bool capture_is_combined_plane = drm_fd->is_combined_plane || ((int)drm_fd->width == cap_kms->screen_size.x && (int)drm_fd->height == cap_kms->screen_size.y); + //bool capture_is_combined_plane = drm_fd->is_combined_plane || ((int)drm_fd->width == cap_kms->screen_size.x && (int)drm_fd->height == cap_kms->screen_size.y); // TODO: This causes a crash sometimes on steam deck, why? is it a driver bug? a vaapi pure version doesn't cause a crash. // Even ffmpeg kmsgrab causes this crash. The error is: @@ -592,44 +487,40 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { 0.0f); } else { float texture_rotation = 0.0f; - if(requires_rotation) { - switch(cap_kms->x11_rot) { - case X11_ROT_90: - texture_rotation = M_PI*0.5f; - break; - case X11_ROT_180: - texture_rotation = M_PI; - break; - case X11_ROT_270: - texture_rotation = M_PI*1.5f; - break; - default: - texture_rotation = 0.0f; - break; - } - } - - if(cap_kms->params.dpy && !cap_kms->params.wayland) { - gsr_cursor_tick(&cap_kms->cursor); - } vec2i capture_pos = cap_kms->capture_pos; vec2i capture_size = cap_kms->capture_size; - vec2i cursor_capture_pos = (vec2i){cap_kms->cursor.position.x - cap_kms->cursor.hotspot.x - capture_pos.x, cap_kms->cursor.position.y - cap_kms->cursor.hotspot.y - capture_pos.y}; - if(!capture_is_combined_plane) { - capture_pos = (vec2i){0, 0}; - //cursor_capture_pos = (vec2i){cap_kms->cursor.position.x - cap_kms->cursor.hotspot.x, cap_kms->cursor.position.y - cap_kms->cursor.hotspot.y}; - } + capture_pos = (vec2i){drm_fd->x, drm_fd->y}; + capture_size = (vec2i){drm_fd->src_w, drm_fd->src_h}; gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture, (vec2i){0, 0}, capture_size, capture_pos, capture_size, texture_rotation); - if(cap_kms->params.dpy && !cap_kms->params.wayland) { - gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor.texture_id, - cursor_capture_pos, (vec2i){cap_kms->cursor.size.x, cap_kms->cursor.size.y}, - (vec2i){0, 0}, (vec2i){cap_kms->cursor.size.x, cap_kms->cursor.size.y}, + if(cursor_drm_fd) { + const intptr_t img_attr[] = { + EGL_LINUX_DRM_FOURCC_EXT, cursor_drm_fd->pixel_format, + EGL_WIDTH, cursor_drm_fd->width, + EGL_HEIGHT, cursor_drm_fd->height, + EGL_DMA_BUF_PLANE0_FD_EXT, cursor_drm_fd->fd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, cursor_drm_fd->offset, + EGL_DMA_BUF_PLANE0_PITCH_EXT, cursor_drm_fd->pitch, + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, cursor_drm_fd->modifier & 0xFFFFFFFFULL, + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, cursor_drm_fd->modifier >> 32ULL, + EGL_NONE + }; + + EGLImage image = cap_kms->params.egl->eglCreateImage(cap_kms->params.egl->egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, img_attr); + cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, cap_kms->cursor_texture); + cap_kms->params.egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, image); + cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0); + + vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height}; + gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor_texture, + (vec2i){cursor_drm_fd->x, cursor_drm_fd->y}, cursor_size, + (vec2i){0, 0}, cursor_size, 0.0f); } } @@ -651,7 +542,6 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { static void gsr_capture_kms_vaapi_stop(gsr_capture *cap, AVCodecContext *video_codec_context) { gsr_capture_kms_vaapi *cap_kms = cap->priv; - gsr_cursor_deinit(&cap_kms->cursor); gsr_color_conversion_deinit(&cap_kms->color_conversion); for(uint32_t i = 0; i < cap_kms->prime.num_objects; ++i) { @@ -667,6 +557,11 @@ static void gsr_capture_kms_vaapi_stop(gsr_capture *cap, AVCodecContext *video_c cap_kms->input_texture = 0; } + if(cap_kms->cursor_texture) { + cap_kms->params.egl->glDeleteTextures(1, &cap_kms->cursor_texture); + cap_kms->cursor_texture = 0; + } + cap_kms->params.egl->glDeleteTextures(2, cap_kms->target_textures); cap_kms->target_textures[0] = 0; cap_kms->target_textures[1] = 0; diff --git a/src/main.cpp b/src/main.cpp index cec3bca..c5dd33f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1389,8 +1389,7 @@ int main(int argc, char **argv) { follow_focused = true; } else if(contains_non_hex_number(window_str)) { - // TODO: wayland, not only drm (if wlroots) - if(wayland) { + if(wayland || gpu_inf.vendor != GSR_GPU_VENDOR_NVIDIA) { if(gsr_egl_supports_wayland_capture(&egl)) { gsr_monitor gmon; if(!get_monitor_by_name(&egl, GSR_CONNECTION_WAYLAND, window_str, &gmon)) { @@ -1472,7 +1471,6 @@ int main(int argc, char **argv) { gsr_capture_kms_vaapi_params kms_params; kms_params.egl = &egl; - kms_params.dpy = dpy; kms_params.display_to_capture = capture_target; kms_params.gpu_inf = gpu_inf; kms_params.card_path = card_path; -- cgit v1.2.3