Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux-pipewire: Add explicit sync support #11708

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions deps/glad/include/glad/glad_egl.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*

EGL loader generated by glad 0.1.36 on Sat Jan 27 07:23:01 2024.
EGL loader generated by glad 0.1.36 on Tue Oct 22 13:32:48 2024.

Language/Generator: C/C++
Specification: egl
APIs: egl=1.5
Profile: -
Extensions:
EGL_ANDROID_native_fence_sync,
EGL_EXT_device_base,
EGL_EXT_device_drm_render_node,
EGL_EXT_image_dma_buf_import,
Expand All @@ -27,9 +28,9 @@
Reproducible: False

Commandline:
--api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_EXT_device_base,EGL_EXT_device_drm_render_node,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_platform_base,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_platform_xcb,EGL_KHR_create_context,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_image_dma_buf_export"
--api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_ANDROID_native_fence_sync,EGL_EXT_device_base,EGL_EXT_device_drm_render_node,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_platform_base,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_platform_xcb,EGL_KHR_create_context,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_image_dma_buf_export"
Online:
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_EXT_device_base&extensions=EGL_EXT_device_drm_render_node&extensions=EGL_EXT_image_dma_buf_import&extensions=EGL_EXT_image_dma_buf_import_modifiers&extensions=EGL_EXT_platform_base&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_EXT_platform_xcb&extensions=EGL_KHR_create_context&extensions=EGL_KHR_image_base&extensions=EGL_KHR_image_pixmap&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11&extensions=EGL_MESA_image_dma_buf_export
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_ANDROID_native_fence_sync&extensions=EGL_EXT_device_base&extensions=EGL_EXT_device_drm_render_node&extensions=EGL_EXT_image_dma_buf_import&extensions=EGL_EXT_image_dma_buf_import_modifiers&extensions=EGL_EXT_platform_base&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_EXT_platform_xcb&extensions=EGL_KHR_create_context&extensions=EGL_KHR_image_base&extensions=EGL_KHR_image_pixmap&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11&extensions=EGL_MESA_image_dma_buf_export
*/


Expand Down Expand Up @@ -322,6 +323,10 @@ EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const E
EGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
EGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);
#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0)
#define EGL_BAD_DEVICE_EXT 0x322B
#define EGL_DEVICE_EXT 0x322C
Expand Down Expand Up @@ -383,6 +388,12 @@ EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);
#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
#define EGL_PLATFORM_X11_KHR 0x31D5
#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
#ifndef EGL_ANDROID_native_fence_sync
#define EGL_ANDROID_native_fence_sync 1
typedef EGLint (APIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR sync);
GLAPI PFNEGLDUPNATIVEFENCEFDANDROIDPROC glad_eglDupNativeFenceFDANDROID;
#define eglDupNativeFenceFDANDROID glad_eglDupNativeFenceFDANDROID
#endif
#ifndef EGL_EXT_device_base
#define EGL_EXT_device_base 1
typedef EGLBoolean (APIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC)(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
Expand Down
12 changes: 9 additions & 3 deletions deps/glad/src/glad_egl.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*

EGL loader generated by glad 0.1.36 on Sat Jan 27 07:23:01 2024.
EGL loader generated by glad 0.1.36 on Tue Oct 22 13:32:48 2024.

Language/Generator: C/C++
Specification: egl
APIs: egl=1.5
Profile: -
Extensions:
EGL_ANDROID_native_fence_sync,
EGL_EXT_device_base,
EGL_EXT_device_drm_render_node,
EGL_EXT_image_dma_buf_import,
Expand All @@ -27,9 +28,9 @@
Reproducible: False

Commandline:
--api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_EXT_device_base,EGL_EXT_device_drm_render_node,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_platform_base,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_platform_xcb,EGL_KHR_create_context,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_image_dma_buf_export"
--api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_ANDROID_native_fence_sync,EGL_EXT_device_base,EGL_EXT_device_drm_render_node,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_platform_base,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_platform_xcb,EGL_KHR_create_context,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_image_dma_buf_export"
Online:
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_EXT_device_base&extensions=EGL_EXT_device_drm_render_node&extensions=EGL_EXT_image_dma_buf_import&extensions=EGL_EXT_image_dma_buf_import_modifiers&extensions=EGL_EXT_platform_base&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_EXT_platform_xcb&extensions=EGL_KHR_create_context&extensions=EGL_KHR_image_base&extensions=EGL_KHR_image_pixmap&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11&extensions=EGL_MESA_image_dma_buf_export
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_ANDROID_native_fence_sync&extensions=EGL_EXT_device_base&extensions=EGL_EXT_device_drm_render_node&extensions=EGL_EXT_image_dma_buf_import&extensions=EGL_EXT_image_dma_buf_import_modifiers&extensions=EGL_EXT_platform_base&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_EXT_platform_xcb&extensions=EGL_KHR_create_context&extensions=EGL_KHR_image_base&extensions=EGL_KHR_image_pixmap&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11&extensions=EGL_MESA_image_dma_buf_export
*/

#include <stdio.h>
Expand All @@ -41,6 +42,7 @@ int gladLoadEGL(void) {
return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress);
}

PFNEGLDUPNATIVEFENCEFDANDROIDPROC glad_eglDupNativeFenceFDANDROID = NULL;
PFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT = NULL;
PFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT = NULL;
PFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT = NULL;
Expand All @@ -54,6 +56,9 @@ PFNEGLCREATEIMAGEKHRPROC glad_eglCreateImageKHR = NULL;
PFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR = NULL;
PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC glad_eglExportDMABUFImageQueryMESA = NULL;
PFNEGLEXPORTDMABUFIMAGEMESAPROC glad_eglExportDMABUFImageMESA = NULL;
static void load_EGL_ANDROID_native_fence_sync(GLADloadproc load) {
glad_eglDupNativeFenceFDANDROID = (PFNEGLDUPNATIVEFENCEFDANDROIDPROC)load("eglDupNativeFenceFDANDROID");
}
static void load_EGL_EXT_device_base(GLADloadproc load) {
glad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC)load("eglQueryDeviceAttribEXT");
glad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)load("eglQueryDeviceStringEXT");
Expand Down Expand Up @@ -89,6 +94,7 @@ int gladLoadEGLLoader(GLADloadproc load) {
find_coreEGL();

if (!find_extensionsEGL()) return 0;
load_EGL_ANDROID_native_fence_sync(load);
load_EGL_EXT_device_base(load);
load_EGL_EXT_image_dma_buf_import_modifiers(load);
load_EGL_EXT_platform_base(load);
Expand Down
86 changes: 86 additions & 0 deletions docs/sphinx/reference-libobs-graphics-graphics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,91 @@ Texture Functions

---------------------

.. function:: bool gs_query_sync_capabilities(void)

**only Linux, FreeBSD, DragonFly:** Checks if the use of synchronization objects is supported

:rtype: bool
:return: *true* if supported, *false* otherwise

---------------------

.. function:: gs_sync_t *gs_sync_create(void)

**only Linux, FreeBSD, DragonFly:** Creates a synchronization object

Inserts a fence command into the command stream of the bound context and
creates a synchronization object that is signalled when all the commands
preceding the inserted fence are executed.

:rtype: gs_sync_t*

---------------------

.. function:: gs_sync_t *gs_sync_create_from_syncobj_timeline_point(int syncobj_fd, uint64_t timeline_point)

**only Linux, FreeBSD, DragonFly:** Creates a synchronization object

Creates a synchronization object that is signalled when the specified
timeline point of the given DRM syncobj is signalled.

:param syncobj_fd: A file descriptor that is referencing a DRM syncobj
:param timeline_point: Timeline point of the DRM syncobj
:rtype: gs_sync_t*

---------------------

.. function:: void gs_sync_destroy(gs_sync_t *sync)

**only Linux, FreeBSD, DragonFly:** Destroys a synchronization object

If the given synchronization object is in use, it will be marked for
destruction and will be destroyed later when it is no longer referenced.

:param sync: Synchronization object

---------------------

.. function:: bool gs_sync_export_syncobj_timeline_point(gs_sync_t *sync, int syncobj_fd, uint64_t timeline_point)

**only Linux, FreeBSD, DragonFly:** Exports a synchronization object to a DRM syncobj timeline point

Creates a DRM syncobj timeline point that is signalled when the given
synchronization object is signalled.

:param sync: Synchronization object
:param syncobj_fd: A file descriptor that is referencing a DRM syncobj
:param timeline_point: Timeline point of the DRM syncobj
:rtype: bool
:return: *true* if the synchronization object is exported successfully, *false* otherwise

---------------------

.. function:: bool gs_sync_signal_syncobj_timeline_point(int syncobj_fd, uint64_t timeline_point)

**only Linux, FreeBSD, DragonFly:** Signals a DRM syncobj timeline point

:param syncobj_fd: A file descriptor that is referencing a DRM syncobj
:param timeline_point: Timeline point of the DRM syncobj
:rtype: bool
:return: *true* if the timeline point is signalled successfully, *false* otherwise

---------------------

.. function:: bool gs_sync_wait(gs_sync_t *sync)

**only Linux, FreeBSD, DragonFly:** Wait for a synchronization object to be signalled

Blocks the execution of the commands that would be inserted into the command
stream of the bound context until the given synchronization object is
signalled.

:param sync: Synchronization object
:rtype: bool
:return: *true* if successful, *false* otherwise

---------------------

.. function:: gs_texture_t *gs_texture_create_from_iosurface(void *iosurf)

**macOS only:** Creates a texture from an IOSurface.
Expand Down Expand Up @@ -1586,4 +1671,5 @@ Graphics Types
.. type:: struct gs_shader gs_shader_t
.. type:: struct gs_shader_param gs_sparam_t
.. type:: struct gs_device gs_device_t
.. type:: void gs_sync_t
.. type:: struct graphics_subsystem graphics_t
2 changes: 2 additions & 0 deletions libobs-opengl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if(NOT TARGET OBS::glad)
endif()

if(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD)
find_package(Libdrm REQUIRED)
find_package(X11 REQUIRED)
find_package(Xcb REQUIRED xcb)
find_package(X11-xcb REQUIRED)
Expand Down Expand Up @@ -54,6 +55,7 @@ target_link_libraries(
OBS::glad
"$<$<PLATFORM_ID:Darwin>:$<LINK_LIBRARY:FRAMEWORK,Cocoa.framework>>"
"$<$<PLATFORM_ID:Darwin>:$<LINK_LIBRARY:FRAMEWORK,IOSurface.framework>>"
$<$<PLATFORM_ID:Linux,FreeBSD,OpenBSD>:Libdrm::Libdrm>
$<$<PLATFORM_ID:Linux,FreeBSD,OpenBSD>:xcb::xcb>
$<$<PLATFORM_ID:Linux,FreeBSD,OpenBSD>:X11::x11-xcb>
$<$<AND:$<PLATFORM_ID:Linux,FreeBSD,OpenBSD>,$<BOOL:${ENABLE_WAYLAND}>>:OpenGL::EGL>
Expand Down
115 changes: 115 additions & 0 deletions libobs-opengl/gl-egl-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

#include <linux/types.h>
#include <asm/ioctl.h>
#include <xf86drm.h>
#include <unistd.h>
#include <fcntl.h>
typedef unsigned int drm_handle_t;

#else
Expand Down Expand Up @@ -392,6 +395,95 @@ bool gl_egl_query_dmabuf_modifiers_for_format(EGLDisplay egl_display, uint32_t d
return true;
}

bool gl_egl_query_sync_capabilities(int drm_fd)
{
uint64_t syncobjCap = 0;
uint64_t syncobjTimelineCap = 0;

drmGetCap(drm_fd, DRM_CAP_SYNCOBJ, &syncobjCap);
drmGetCap(drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &syncobjTimelineCap);
return syncobjCap && syncobjTimelineCap && (EGL_ANDROID_native_fence_sync > 0);
}

gs_sync_t *gl_egl_create_sync(EGLDisplay egl_display)
{
gs_sync_t *sync = eglCreateSync(egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
glFlush();
kkartaltepe marked this conversation as resolved.
Show resolved Hide resolved
return sync;
}

gs_sync_t *gl_egl_create_sync_from_syncobj_timeline_point(EGLDisplay egl_display, int drm_fd, int syncobj_fd,
uint64_t timeline_point)
{
EGLSync sync;
int syncfile_fd = -1;
uint32_t syncobj_handle = 0;
uint32_t temp_handle = 0;

drmSyncobjFDToHandle(drm_fd, syncobj_fd, &syncobj_handle);
drmSyncobjTimelineWait(drm_fd, &syncobj_handle, &timeline_point, 1, INT64_MAX,
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE, NULL);
drmSyncobjCreate(drm_fd, 0, &temp_handle);
drmSyncobjTransfer(drm_fd, temp_handle, 0, syncobj_handle, timeline_point, 0);
drmSyncobjExportSyncFile(drm_fd, temp_handle, &syncfile_fd);
drmSyncobjDestroy(drm_fd, temp_handle);
drmSyncobjDestroy(drm_fd, syncobj_handle);

const EGLAttrib attributes[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, syncfile_fd, EGL_NONE};

sync = eglCreateSync(egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attributes);
if (sync == EGL_NO_SYNC) {
blog(LOG_ERROR, "Unable to create an EGLSync object from a syncfile fd");
close(syncfile_fd);
}

return sync;
}

bool gl_egl_sync_export_syncobj_timeline_point(EGLDisplay egl_display, gs_sync_t *sync, int drm_fd, int syncobj_fd,
uint64_t timeline_point)
{
uint32_t syncobj_handle = 0;
uint32_t temp_handle = 0;

int gs_sync_fd = eglDupNativeFenceFDANDROID(egl_display, sync);
if (gs_sync_fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
return false;
}

drmSyncobjFDToHandle(drm_fd, syncobj_fd, &syncobj_handle);
drmSyncobjCreate(drm_fd, 0, &temp_handle);
drmSyncobjImportSyncFile(drm_fd, temp_handle, gs_sync_fd);
drmSyncobjTransfer(drm_fd, syncobj_handle, timeline_point, temp_handle, 0, 0);
drmSyncobjDestroy(drm_fd, temp_handle);
drmSyncobjDestroy(drm_fd, syncobj_handle);
close(gs_sync_fd);

return true;
}

bool gl_egl_sync_signal_syncobj_timeline_point(int drm_fd, int syncobj_fd, uint64_t timeline_point)
{
uint32_t syncobj_handle = 0;
bool result;

drmSyncobjFDToHandle(drm_fd, syncobj_fd, &syncobj_handle);
result = drmSyncobjTimelineSignal(drm_fd, &syncobj_handle, &timeline_point, 1) == 0;
drmSyncobjDestroy(drm_fd, syncobj_handle);

return result;
}

void gl_egl_device_sync_destroy(EGLDisplay egl_display, gs_sync_t *sync)
{
eglDestroySync(egl_display, sync);
}

bool gl_egl_sync_wait(EGLDisplay egl_display, gs_sync_t *sync)
{
return eglWaitSync(egl_display, sync, 0);
}

const char *gl_egl_error_to_string(EGLint error_number)
{
switch (error_number) {
Expand Down Expand Up @@ -445,3 +537,26 @@ const char *gl_egl_error_to_string(EGLint error_number)
break;
}
}

int get_drm_render_node_fd(EGLDisplay egl_display)
{
EGLAttrib attrib;
EGLDeviceEXT device;
const char *drm_render_node_path;

if (eglQueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &attrib) != EGL_TRUE) {
return -1;
}
device = (EGLDeviceEXT)attrib;
drm_render_node_path = eglQueryDeviceStringEXT(device, EGL_DRM_RENDER_NODE_FILE_EXT);
if (drm_render_node_path == NULL) {
return -1;
}

return open(drm_render_node_path, O_RDWR | O_CLOEXEC);
}

void close_drm_render_node_fd(int fd)
{
close(fd);
}
20 changes: 20 additions & 0 deletions libobs-opengl/gl-egl-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

const char *gl_egl_error_to_string(EGLint error_number);

int get_drm_render_node_fd(EGLDisplay egl_display);

void close_drm_render_node_fd(int fd);

struct gs_texture *gl_egl_create_dmabuf_image(EGLDisplay egl_display, unsigned int width, unsigned int height,
uint32_t drm_format, enum gs_color_format color_format, uint32_t n_planes,
const int *fds, const uint32_t *strides, const uint32_t *offsets,
Expand All @@ -24,3 +28,19 @@ struct gs_texture *gl_egl_create_texture_from_pixmap(EGLDisplay egl_display, uin
bool gl_egl_enum_adapters(EGLDisplay display, bool (*callback)(void *param, const char *name, uint32_t id),
void *param);
uint32_t gs_get_adapter_count();

bool gl_egl_query_sync_capabilities(int drm_fd);

gs_sync_t *gl_egl_create_sync(EGLDisplay egl_display);

gs_sync_t *gl_egl_create_sync_from_syncobj_timeline_point(EGLDisplay egl_display, int drm_fd, int syncobj_fd,
uint64_t timeline_point);

void gl_egl_device_sync_destroy(EGLDisplay egl_display, gs_sync_t *sync);

bool gl_egl_sync_export_syncobj_timeline_point(EGLDisplay egl_display, gs_sync_t *sync, int drm_fd, int syncobj_fd,
uint64_t timeline_point);

bool gl_egl_sync_signal_syncobj_timeline_point(int drm_fd, int syncobj_fd, uint64_t timeline_point);

bool gl_egl_sync_wait(EGLDisplay egl_display, gs_sync_t *sync);
Loading
Loading