aboutsummaryrefslogtreecommitdiff
path: root/src/pipewire.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-07-22 01:24:23 +0200
committerdec05eba <dec05eba@protonmail.com>2024-07-22 01:24:23 +0200
commit37107bac8d1088f4f541afe99a7c9aea0801e99d (patch)
tree8ceace3ce014ca92591e36443cbeddea612e89f4 /src/pipewire.c
parentf9a41041ec3c2f88033f1ec0dd32ed0270b75c2f (diff)
Fix deskto portal capture on nvidia (add missing modifiers)
Diffstat (limited to 'src/pipewire.c')
-rw-r--r--src/pipewire.c74
1 files changed, 51 insertions, 23 deletions
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");