1
0
Эх сурвалжийг харах

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.
Ivan Molodetskikh 3 сар өмнө
parent
commit
a7de3f4bde

+ 12 - 2
plugins/linux-pipewire/pipewire.c

@@ -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);
 }