linux-pipewire: Dup syncobj fds

PipeWire format renegotiation runs in parallel with video rendering.

When the stream format is renegotiated, PipeWire removes the existing
buffers and closes the syncobj file descriptors. At the same time, the
video rendering thread may try to import the (already closed) syncobj
acquire fd, and hang on waiting for the fence to become available.

This is not a problem for the dmabuf fd because it's imported into a
texture right away, which doesn't disappear when PipeWire closes the fd.

This commit adds duping to the syncobj fds so that they too remain open
as long as the rendering thread may access them.
This commit is contained in:
Ivan Molodetskikh
2025-07-20 09:32:18 +03:00
committed by Ryan Foster
parent 7092bc17db
commit a7de3f4bde
+12 -2
View File
@@ -26,6 +26,7 @@
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include <glib/gstdio.h>
#include <fcntl.h>
#include <glad/glad.h>
@@ -765,14 +766,18 @@ static void process_video_sync(obs_pipewire_stream *obs_pw_stream)
}
#if PW_CHECK_VERSION(1, 2, 0)
g_clear_fd(&obs_pw_stream->sync.acquire_syncobj_fd, NULL);
g_clear_fd(&obs_pw_stream->sync.release_syncobj_fd, NULL);
if (synctimeline && (buffer->n_datas == (planes + 2))) {
assert(buffer->datas[planes].type == SPA_DATA_SyncObj);
assert(buffer->datas[planes + 1].type == SPA_DATA_SyncObj);
obs_pw_stream->sync.acquire_syncobj_fd = buffer->datas[planes].fd;
obs_pw_stream->sync.acquire_syncobj_fd = fcntl(buffer->datas[planes].fd, F_DUPFD_CLOEXEC, 5);
obs_pw_stream->sync.acquire_point = synctimeline->acquire_point;
obs_pw_stream->sync.release_syncobj_fd = buffer->datas[planes + 1].fd;
obs_pw_stream->sync.release_syncobj_fd =
fcntl(buffer->datas[planes + 1].fd, F_DUPFD_CLOEXEC, 5);
obs_pw_stream->sync.release_point = synctimeline->release_point;
obs_pw_stream->sync.set = true;
@@ -1179,6 +1184,8 @@ obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_sourc
obs_pw_stream->cursor.visible = connect_info->screencast.cursor_visible;
obs_pw_stream->framerate.set = connect_info->video.framerate != NULL;
obs_pw_stream->resolution.set = connect_info->video.resolution != NULL;
obs_pw_stream->sync.acquire_syncobj_fd = -1;
obs_pw_stream->sync.release_syncobj_fd = -1;
if (obs_pw_stream->framerate.set)
obs_pw_stream->framerate.fraction = *connect_info->video.framerate;
@@ -1409,6 +1416,9 @@ void obs_pipewire_stream_destroy(obs_pipewire_stream *obs_pw_stream)
g_clear_pointer(&obs_pw_stream->stream, pw_stream_destroy);
pw_thread_loop_unlock(obs_pw_stream->obs_pw->thread_loop);
g_clear_fd(&obs_pw_stream->sync.acquire_syncobj_fd, NULL);
g_clear_fd(&obs_pw_stream->sync.release_syncobj_fd, NULL);
clear_format_info(obs_pw_stream);
bfree(obs_pw_stream);
}