diff options
-rw-r--r-- | com.dec05eba.gpu_screen_recorder.appdata.xml | 9 | ||||
-rw-r--r-- | src/egl.c | 17 | ||||
-rw-r--r-- | src/egl.h | 10 | ||||
-rw-r--r-- | src/main.cpp | 99 |
4 files changed, 97 insertions, 38 deletions
diff --git a/com.dec05eba.gpu_screen_recorder.appdata.xml b/com.dec05eba.gpu_screen_recorder.appdata.xml index 1577b5c..0336ecf 100644 --- a/com.dec05eba.gpu_screen_recorder.appdata.xml +++ b/com.dec05eba.gpu_screen_recorder.appdata.xml @@ -75,6 +75,15 @@ </screenshots> <releases> + <release version="3.6.0" date="2024-03-10"> + <description> + <ul> + <li>Support HDR capture and full color range on nvidia</li> + <li>Support cursor capture when recording a single window</li> + <li>Show the correct monitors when using prime-run</li> + </ul> + </description> + </release> <release version="3.5.3" date="2024-02-16"> <description> <p>Fix minor permissions issue</p> @@ -221,6 +221,7 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) { { (void**)&self->eglDestroyContext, "eglDestroyContext" }, { (void**)&self->eglDestroySurface, "eglDestroySurface" }, { (void**)&self->eglBindAPI, "eglBindAPI" }, + { (void**)&self->eglGetProcAddress, "eglGetProcAddress" }, { NULL, NULL } }; @@ -248,6 +249,13 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) { return true; } +static bool gsr_egl_proc_load_egl(gsr_egl *self) { + self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT"); + self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT"); + + return true; +} + bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland) { memset(self, 0, sizeof(gsr_egl)); self->x11.dpy = dpy; @@ -274,9 +282,18 @@ bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland) { if(!gsr_egl_load_gl(self, gl_lib)) goto fail; + if(!gsr_egl_proc_load_egl(self)) + goto fail; + if(!gsr_egl_create_window(self, wayland)) goto fail; + if(self->eglQueryDisplayAttribEXT && self->eglQueryDeviceStringEXT) { + intptr_t device = 0; + if(self->eglQueryDisplayAttribEXT(self->egl_display, EGL_DEVICE_EXT, &device) && device) + self->dri_card_path = self->eglQueryDeviceStringEXT((void*)device, EGL_DRM_DEVICE_FILE_EXT); + } + self->egl_library = egl_lib; self->gl_library = gl_lib; return true; @@ -37,12 +37,17 @@ typedef void* EGLImageKHR; typedef void *GLeglImageOES; typedef void (*__eglMustCastToProperFunctionPointerType)(void); +typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value); +typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name); + #define EGL_BUFFER_SIZE 0x3020 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_OPENGL_BIT 0x0008 #define EGL_OPENGL_API 0x30A2 #define EGL_NONE 0x3038 #define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_DEVICE_EXT 0x322C +#define EGL_DRM_DEVICE_FILE_EXT 0x3233 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 @@ -79,6 +84,7 @@ typedef struct { EGLDisplay egl_display; EGLSurface egl_surface; EGLContext egl_context; + const char *dri_card_path; gsr_x11 x11; gsr_wayland wayland; @@ -94,6 +100,10 @@ typedef struct { unsigned int (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); unsigned int (*eglBindAPI)(unsigned int api); + __eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname); + + FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT; + FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT; const unsigned char* (*glGetString)(unsigned int name); } gsr_egl; diff --git a/src/main.cpp b/src/main.cpp index d676e00..d6615f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -825,48 +825,60 @@ static void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_ty } } -/* output should be >= 128 bytes */ -static bool gsr_get_valid_card_path(char *output) { - for(int i = 0; i < 10; ++i) { - drmVersion *ver = NULL; - drmModePlaneResPtr planes = NULL; - bool found_screen_card = false; - - sprintf(output, DRM_DEV_NAME, DRM_DIR_NAME, i); - int fd = open(output, O_RDONLY); - if(fd == -1) - continue; +static bool try_card_has_valid_plane(const char *card_path) { + drmVersion *ver = NULL; + drmModePlaneResPtr planes = NULL; + bool found_screen_card = false; - ver = drmGetVersion(fd); - if(!ver || strstr(ver->name, "nouveau")) - goto next; + int fd = open(card_path, O_RDONLY); + if(fd == -1) + return false; - drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + ver = drmGetVersion(fd); + if(!ver || strstr(ver->name, "nouveau")) + goto next; - planes = drmModeGetPlaneResources(fd); - if(!planes) - goto next; + drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - for(uint32_t i = 0; i < planes->count_planes; ++i) { - drmModePlanePtr plane = drmModeGetPlane(fd, planes->planes[i]); - if(!plane) - continue; + planes = drmModeGetPlaneResources(fd); + if(!planes) + goto next; - if(plane->fb_id) - found_screen_card = true; + for(uint32_t j = 0; j < planes->count_planes; ++j) { + drmModePlanePtr plane = drmModeGetPlane(fd, planes->planes[j]); + if(!plane) + continue; - drmModeFreePlane(plane); - if(found_screen_card) - break; - } + if(plane->fb_id) + found_screen_card = true; - next: - if(planes) - drmModeFreePlaneResources(planes); - if(ver) - drmFreeVersion(ver); - close(fd); + drmModeFreePlane(plane); if(found_screen_card) + break; + } + + next: + if(planes) + drmModeFreePlaneResources(planes); + if(ver) + drmFreeVersion(ver); + close(fd); + if(found_screen_card) + return true; + + return false; +} + +/* output should be >= 128 bytes */ +static bool gsr_get_valid_card_path(gsr_egl *egl, char *output) { + if(egl->dri_card_path) { + strncpy(output, egl->dri_card_path, 128); + return try_card_has_valid_plane(output); + } + + for(int i = 0; i < 10; ++i) { + snprintf(output, 128, DRM_DEV_NAME, DRM_DIR_NAME, i); + if(try_card_has_valid_plane(output)) return true; } return false; @@ -2436,8 +2448,10 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a gtk_combo_box_text_append(video_codec_input_menu, "av1", "AV1"); if(wayland) { - gtk_combo_box_text_append(video_codec_input_menu, "hevc_hdr", "HEVC (HDR)"); - gtk_combo_box_text_append(video_codec_input_menu, "av1_hdr", "AV1 (HDR)"); + if(supported_video_codecs.hevc) + gtk_combo_box_text_append(video_codec_input_menu, "hevc_hdr", "HEVC (HDR)"); + if(supported_video_codecs.av1) + gtk_combo_box_text_append(video_codec_input_menu, "av1_hdr", "AV1 (HDR)"); } } else { gtk_combo_box_text_append(video_codec_input_menu, "h264", "H264"); @@ -3143,6 +3157,15 @@ static void load_config(const gpu_info &gpu_inf) { return; } } + + if(!supported_video_codecs.h264 && !supported_video_codecs.hevc && gpu_inf.vendor == GPU_VENDOR_NVIDIA) { + GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "Failed to find H264/HEVC video codecs. Your NVIDIA GPU may be missing support for H264/HEVC video codecs for video encoding."); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + g_application_quit(G_APPLICATION(select_window_userdata.app)); + return; + } } static bool gl_get_gpu_info(gsr_egl *egl, gpu_info *info) { @@ -3250,9 +3273,9 @@ static void activate(GtkApplication *app, gpointer) { } if((gpu_inf.vendor != GPU_VENDOR_NVIDIA) || wayland) { - if(!gsr_get_valid_card_path(egl.card_path)) { + if(!gsr_get_valid_card_path(&egl, egl.card_path)) { GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "Failed to find a valid DRM card."); + "Failed to find a valid DRM card. If you are using prime-run then run without it."); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); g_application_quit(G_APPLICATION(app)); |