From 37107bac8d1088f4f541afe99a7c9aea0801e99d Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 22 Jul 2024 01:24:23 +0200 Subject: Fix deskto portal capture on nvidia (add missing modifiers) --- include/egl.h | 7 ++--- src/capture/kms.c | 1 + src/capture/xcomposite.c | 10 ------- src/egl.c | 3 +- src/pipewire.c | 74 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 55 insertions(+), 40 deletions(-) diff --git a/include/egl.h b/include/egl.h index 1bf3535..c86cb6b 100644 --- a/include/egl.h +++ b/include/egl.h @@ -31,7 +31,6 @@ typedef void* EGLSurface; typedef void* EGLContext; typedef void* EGLClientBuffer; typedef void* EGLImage; -typedef void* EGLImageKHR; typedef void *GLeglImageOES; typedef void (*__eglMustCastToProperFunctionPointerType)(void); typedef struct __GLXFBConfigRec *GLXFBConfig; @@ -122,8 +121,6 @@ typedef void(*__GLXextFuncPtr)(void); #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 -typedef unsigned int (*FUNC_eglExportDMABUFImageQueryMESA)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, uint64_t *modifiers); -typedef unsigned int (*FUNC_eglExportDMABUFImageMESA)(EGLDisplay dpy, EGLImageKHR image, int *fds, int32_t *strides, int32_t *offsets); typedef void (*FUNC_glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image); typedef GLXContext (*FUNC_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval); @@ -132,6 +129,7 @@ typedef int (*FUNC_glXSwapIntervalSGI)(int interval); typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char *message, const void *userParam); typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value); typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name); +typedef int (*FUNC_eglQueryDmaBufModifiersEXT)(EGLDisplay dpy, int32_t format, int32_t max_modifiers, uint64_t *modifiers, int *external_only, int32_t *num_modifiers); #define GSR_MAX_OUTPUTS 32 @@ -203,11 +201,10 @@ struct gsr_egl { unsigned int (*eglBindAPI)(unsigned int api); __eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname); - FUNC_eglExportDMABUFImageQueryMESA eglExportDMABUFImageQueryMESA; - FUNC_eglExportDMABUFImageMESA eglExportDMABUFImageMESA; FUNC_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES; FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT; FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT; + FUNC_eglQueryDmaBufModifiersEXT eglQueryDmaBufModifiersEXT; __GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName); GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems); diff --git a/src/capture/kms.c b/src/capture/kms.c index c078b90..50fe01a 100644 --- a/src/capture/kms.c +++ b/src/capture/kms.c @@ -232,6 +232,7 @@ static bool hdr_metadata_is_supported_format(const struct hdr_output_metadata *h hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084; } +// TODO: Check if this hdr data can be changed after the call to av_packet_side_data_add static void gsr_kms_set_hdr_metadata(gsr_capture_kms *self, AVStream *video_stream, gsr_kms_response_fd *drm_fd) { if(self->hdr_metadata_set) return; diff --git a/src/capture/xcomposite.c b/src/capture/xcomposite.c index d9cb595..52afc20 100644 --- a/src/capture/xcomposite.c +++ b/src/capture/xcomposite.c @@ -133,16 +133,6 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_ // TODO: Get select and add these on top of it and then restore at the end. Also do the same in other xcomposite XSelectInput(self->params.egl->x11.dpy, self->window, StructureNotifyMask | ExposureMask); - if(!self->params.egl->eglExportDMABUFImageQueryMESA) { - fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: could not find eglExportDMABUFImageQueryMESA\n"); - return -1; - } - - if(!self->params.egl->eglExportDMABUFImageMESA) { - fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: could not find eglExportDMABUFImageMESA\n"); - return -1; - } - /* Disable vsync */ self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0); if(window_texture_init(&self->window_texture, self->params.egl->x11.dpy, self->window, self->params.egl) != 0 && !self->params.follow_focused) { diff --git a/src/egl.c b/src/egl.c index c3464b6..3d4c5c7 100644 --- a/src/egl.c +++ b/src/egl.c @@ -358,11 +358,10 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) { } static bool gsr_egl_proc_load_egl(gsr_egl *self) { - self->eglExportDMABUFImageQueryMESA = (FUNC_eglExportDMABUFImageQueryMESA)self->eglGetProcAddress("eglExportDMABUFImageQueryMESA"); - self->eglExportDMABUFImageMESA = (FUNC_eglExportDMABUFImageMESA)self->eglGetProcAddress("eglExportDMABUFImageMESA"); self->glEGLImageTargetTexture2DOES = (FUNC_glEGLImageTargetTexture2DOES)self->eglGetProcAddress("glEGLImageTargetTexture2DOES"); self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT"); self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT"); + self->eglQueryDmaBufModifiersEXT = (FUNC_eglQueryDmaBufModifiersEXT)self->eglGetProcAddress("eglQueryDmaBufModifiersEXT"); if(!self->glEGLImageTargetTexture2DOES) { fprintf(stderr, "gsr error: gsr_egl_load failed: could not find glEGLImageTargetTexture2DOES\n"); diff --git a/src/pipewire.c b/src/pipewire.c index 1870e8a..bba15ac 100644 --- a/src/pipewire.c +++ b/src/pipewire.c @@ -313,7 +313,7 @@ static inline struct spa_pod *build_format(struct spa_pod_builder *b, return spa_pod_builder_pop(b, &format_frame); } -#define NUM_FORMATS 10 +#define NUM_VIDEO_FORMATS 10 /* https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html?gi-language=c#formats */ /* For some reason gstreamer formats are in opposite order to drm formats */ @@ -334,28 +334,56 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format return DRM_FORMAT_INVALID; } +static const enum spa_video_format supported_video_formats[] = { + SPA_VIDEO_FORMAT_BGRx, + SPA_VIDEO_FORMAT_BGRA, + SPA_VIDEO_FORMAT_ABGR, + SPA_VIDEO_FORMAT_xBGR, + SPA_VIDEO_FORMAT_BGR, + SPA_VIDEO_FORMAT_RGBx, + SPA_VIDEO_FORMAT_xRGB, + SPA_VIDEO_FORMAT_RGBA, + SPA_VIDEO_FORMAT_ARGB, + SPA_VIDEO_FORMAT_RGB, +}; + +static void spa_video_format_get_modifiers(gsr_pipewire *self, const enum spa_video_format format, uint64_t *modifiers, int32_t max_modifiers, int32_t *num_modifiers) { + *num_modifiers = 0; + + if(!self->egl->eglQueryDmaBufModifiersEXT) { + fprintf(stderr, "gsr error: spa_video_format_get_modifiers: failed to initialize modifiers because eglQueryDmaBufModifiersEXT is not available\n"); + modifiers[0] = DRM_FORMAT_MOD_LINEAR; + modifiers[1] = DRM_FORMAT_MOD_INVALID; + *num_modifiers = 2; + return; + } + + const int64_t drm_format = spa_video_format_to_drm_format(format); + if(!self->egl->eglQueryDmaBufModifiersEXT(self->egl->egl_display, drm_format, max_modifiers, modifiers, NULL, num_modifiers)) { + fprintf(stderr, "gsr error: spa_video_format_get_modifiers: eglQueryDmaBufModifiersEXT failed with drm format %" PRIi64 "\n", drm_format); + modifiers[0] = DRM_FORMAT_MOD_LINEAR; + modifiers[1] = DRM_FORMAT_MOD_INVALID; + *num_modifiers = 2; + return; + } + + if(*num_modifiers + 2 <= max_modifiers) { + modifiers[*num_modifiers + 0] = DRM_FORMAT_MOD_LINEAR; + modifiers[*num_modifiers + 1] = DRM_FORMAT_MOD_INVALID; + *num_modifiers += 2; + } +} + static bool gsr_pipewire_build_format_params(gsr_pipewire *self, struct spa_pod_builder *pod_builder, struct spa_pod **params) { if(!check_pw_version(&self->server_version, 0, 3, 33)) return false; - const enum spa_video_format formats[] = { - SPA_VIDEO_FORMAT_RGBx, - SPA_VIDEO_FORMAT_BGRx, - SPA_VIDEO_FORMAT_xRGB, - SPA_VIDEO_FORMAT_xBGR, - SPA_VIDEO_FORMAT_RGBA, - SPA_VIDEO_FORMAT_BGRA, - SPA_VIDEO_FORMAT_ARGB, - SPA_VIDEO_FORMAT_ABGR, - SPA_VIDEO_FORMAT_RGB, - SPA_VIDEO_FORMAT_BGR, - }; - - const uint64_t modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; - - for (size_t i = 0; i < NUM_FORMATS; i++) { - enum spa_video_format format = formats[i]; - params[i] = build_format(pod_builder, &self->video_info, format, modifiers, 2); + uint64_t modifiers[1024]; + int32_t num_modifiers = 0; + for(size_t i = 0; i < NUM_VIDEO_FORMATS; i++) { + const enum spa_video_format format = supported_video_formats[i]; + spa_video_format_get_modifiers(self, format, modifiers, sizeof(modifiers), &num_modifiers); + params[i] = build_format(pod_builder, &self->video_info, format, modifiers, num_modifiers); } return true; @@ -367,7 +395,7 @@ static void renegotiate_format(void *data, uint64_t expirations) { pw_thread_loop_lock(self->thread_loop); - struct spa_pod *params[NUM_FORMATS]; + struct spa_pod *params[NUM_VIDEO_FORMATS]; uint8_t params_buffer[2048]; struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); if (!gsr_pipewire_build_format_params(self, &pod_builder, params)) { @@ -375,12 +403,12 @@ static void renegotiate_format(void *data, uint64_t expirations) { return; } - pw_stream_update_params(self->stream, (const struct spa_pod**)params, NUM_FORMATS); + pw_stream_update_params(self->stream, (const struct spa_pod**)params, NUM_VIDEO_FORMATS); pw_thread_loop_unlock(self->thread_loop); } static bool gsr_pipewire_setup_stream(gsr_pipewire *self) { - struct spa_pod *params[NUM_FORMATS]; + struct spa_pod *params[NUM_VIDEO_FORMATS]; uint8_t params_buffer[2048]; struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); @@ -445,7 +473,7 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) { if(pw_stream_connect( self->stream, PW_DIRECTION_INPUT, self->node, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS, (const struct spa_pod**)params, - NUM_FORMATS) < 0) + NUM_VIDEO_FORMATS) < 0) { pw_thread_loop_unlock(self->thread_loop); fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to connect stream\n"); -- cgit v1.2.3