Skip to content

Commit

Permalink
egl-wayland: implement linux-drm-syncobj-v1
Browse files Browse the repository at this point in the history
This implements the explicit sync linux-drm-syncobj-v1 protocol for EGL.

Most of this change involves wayland-protocol handling boilerplate. The
protocol works by allowing the creation of timelines (i.e. DRM syncobjs)
and per-surface states. We can then specify acquire and release points
during our surface state configuration which will tell the compositor
when it can access the buffer or notify us when it is finished accessing
the buffer.

Sync point signaling takes place during acquire_surface_image. We choose
our two release point values and send them to the compositor.  In the
acquire case, the EGLSync will be created first and will be populated
with a fence representing the GPU work. We can extract its syncfd and
import it at the acquire point. We choose the release point during
image acquisition, but don't actually create an EGLSync for it until
later when the compositor has added a fence to the release point. We
check if this has taken place after every surface commit.

Separate timelines are used for the acquire and release points. Each
stream image will have its own timeline, otherwise our signaling of
acquire points would implicitly signal the still-pending release points.
  • Loading branch information
amshafer committed Feb 23, 2024
1 parent 369b337 commit 7a996ad
Show file tree
Hide file tree
Showing 9 changed files with 527 additions and 29 deletions.
14 changes: 14 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ libnvidia_egl_wayland_la_dmabuf_built_client_headers = \
libnvidia_egl_wayland_la_dmabuf_built_private_protocols = \
linux-dmabuf-unstable-v1-protocol.c

libnvidia_egl_wayland_la_drm_syncobj_built_client_headers = \
linux-drm-syncobj-v1-client-protocol.h

libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols = \
linux-drm-syncobj-v1-protocol.c

libnvidia_egl_wayland_la_presentation_time_built_client_headers = \
presentation-time-client-protocol.h

Expand All @@ -93,6 +99,8 @@ libnvidia_egl_wayland_la_built_sources = \
$(libnvidia_egl_wayland_la_built_server_headers) \
$(libnvidia_egl_wayland_la_dmabuf_built_client_headers) \
$(libnvidia_egl_wayland_la_dmabuf_built_private_protocols) \
$(libnvidia_egl_wayland_la_drm_syncobj_built_client_headers) \
$(libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols) \
$(libnvidia_egl_wayland_la_presentation_time_built_client_headers) \
$(libnvidia_egl_wayland_la_presentation_time_private_protocols)

Expand Down Expand Up @@ -129,6 +137,12 @@ $(libnvidia_egl_wayland_la_dmabuf_built_private_protocols):%-protocol.c : $(WAYL
$(libnvidia_egl_wayland_la_dmabuf_built_client_headers):%-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@

$(libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols):%-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/staging/linux-drm-syncobj/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@

$(libnvidia_egl_wayland_la_drm_syncobj_built_client_headers):%-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/staging/linux-drm-syncobj/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@

$(libnvidia_egl_wayland_la_presentation_time_private_protocols):%-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/stable/presentation-time/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@

Expand Down
7 changes: 7 additions & 0 deletions include/wayland-egldisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,17 @@ typedef struct WlEglDmaBufFeedbackRec {
typedef struct WlEglDisplayRec {
WlEglDeviceDpy *devDpy;

/* Supports EGL_ANDROID_native_fence_sync */
int supports_native_fence_sync;

EGLBoolean ownNativeDpy;
struct wl_display *nativeDpy;

struct wl_registry *wlRegistry;
struct wl_eglstream_display *wlStreamDpy;
struct wl_eglstream_controller *wlStreamCtl;
struct zwp_linux_dmabuf_v1 *wlDmaBuf;
struct wp_linux_drm_syncobj_manager_v1 *wlDrmSyncobj;
unsigned int wlStreamCtlVer;
struct wp_presentation *wpPresentation;
struct wl_event_queue *wlEventQueue;
Expand All @@ -139,6 +143,9 @@ typedef struct WlEglDisplayRec {

WlEglPlatformData *data;

/* DRM device in use */
int drmFd;

EGLBoolean useInitRefCount;
EGLDeviceEXT requestedDevice;

Expand Down
2 changes: 2 additions & 0 deletions include/wayland-eglhandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ typedef struct WlEglPlatformDataRec {
PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSync;
PFNEGLSIGNALSYNCKHRPROC signalSync;
PFNEGLDESTROYSYNCKHRPROC destroySync;
PFNEGLCREATESYNCKHRPROC createSync;
PFNEGLSTREAMFLUSHNVPROC streamFlush;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC dupNativeFenceFD;

/* Used for dma-buf surfaces */
PFNEGLSTREAMIMAGECONSUMERCONNECTNVPROC streamImageConsumerConnect;
Expand Down
18 changes: 18 additions & 0 deletions include/wayland-eglsurface-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ typedef struct WlEglStreamImageRec {
struct wl_buffer *buffer;
EGLBoolean attached;
struct wl_list acquiredLink;

struct wp_linux_drm_syncobj_timeline_v1 *wlReleaseTimeline;
uint32_t drmSyncobjHandle;
int releasePending;
/* Latest release point the compositor will signal with explicit sync */
uint64_t releasePoint;
/* Cached acquire EGLSync from acquireImage */
EGLSyncKHR acquireSync;
} WlEglStreamImage;

typedef struct WlEglSurfaceCtxRec {
Expand Down Expand Up @@ -151,6 +159,13 @@ struct WlEglSurfaceRec {
EGLBoolean isResized;

WlEglDmaBufFeedback feedback;

/* per-surface Explicit Sync objects */
struct wp_linux_drm_syncobj_surface_v1 *wlSyncobjSurf;
struct wp_linux_drm_syncobj_timeline_v1 *wlAcquireTimeline;
uint32_t drmSyncobjHandle;
/* Last acquire point used. This starts at 1, zero means invalid. */
uint64_t syncPoint;
};

void wlEglReallocSurface(WlEglDisplay *display,
Expand Down Expand Up @@ -185,6 +200,9 @@ EGLBoolean wlEglQueryNativeResourceHook(EGLDisplay dpy,
EGLint attribute,
int *value);

EGLBoolean
wlEglSurfaceCheckReleasePoints(WlEglDisplay *display, WlEglSurface *surface);

EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface,
struct wl_event_queue *queue);

Expand Down
4 changes: 4 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ libdrm = dependency('libdrm')
wl_protos_dir = wl_protos.get_pkgconfig_variable('pkgdatadir')
wl_dmabuf_xml = join_paths(wl_protos_dir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
wp_presentation_time_xml = join_paths(wl_protos_dir, 'stable', 'presentation-time', 'presentation-time.xml')
wl_drm_syncobj_xml = join_paths(wl_protos_dir, 'staging', 'linux-drm-syncobj', 'linux-drm-syncobj-v1.xml')

client_header = generator(prog_scanner,
output : '@BASENAME@-client-protocol.h',
Expand Down Expand Up @@ -65,6 +66,9 @@ src += code.process(wl_dmabuf_xml)
src += client_header.process(wp_presentation_time_xml)
src += code.process(wp_presentation_time_xml)

src += client_header.process(wl_drm_syncobj_xml)
src += code.process(wl_drm_syncobj_xml)

egl_wayland = library('nvidia-egl-wayland',
src,
dependencies : [
Expand Down
31 changes: 30 additions & 1 deletion src/wayland-egldisplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "wayland-drm-client-protocol.h"
#include "wayland-drm.h"
#include "presentation-time-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
Expand Down Expand Up @@ -454,6 +455,12 @@ registry_handle_global(void *data,
name,
&wp_presentation_interface,
version);
} else if (strcmp(interface, "wp_linux_drm_syncobj_manager_v1") == 0 &&
display->supports_native_fence_sync) {
display->wlDrmSyncobj = wl_registry_bind(registry,
name,
&wp_linux_drm_syncobj_manager_v1_interface,
version);
}
}

Expand Down Expand Up @@ -738,6 +745,10 @@ static EGLBoolean terminateDisplay(WlEglDisplay *display, EGLBoolean globalTeard
wp_presentation_destroy(display->wpPresentation);
display->wpPresentation = NULL;
}
if (display->wlDrmSyncobj) {
wp_linux_drm_syncobj_manager_v1_destroy(display->wlDrmSyncobj);
display->wlDrmSyncobj = NULL;
}
if (display->wlDmaBuf) {
zwp_linux_dmabuf_v1_destroy(display->wlDmaBuf);
display->wlDmaBuf = NULL;
Expand Down Expand Up @@ -926,6 +937,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
EGLDeviceEXT requestedDevice = EGL_NO_DEVICE_EXT;
EGLBoolean usePrimeRenderOffload = EGL_FALSE;
EGLBoolean isServerNV;
const char *drmName = NULL;

if (platform != EGL_PLATFORM_WAYLAND_EXT) {
wlEglSetError(data, EGL_BAD_PARAMETER);
Expand Down Expand Up @@ -1156,7 +1168,6 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
display->primeRenderOffload = EGL_TRUE;
}


display->devDpy = wlGetInternalDisplay(pData, eglDevice);
if (display->devDpy == NULL) {
goto fail;
Expand All @@ -1168,6 +1179,17 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
display->refCount = 1;
WL_LIST_INIT(&display->wlEglSurfaceList);

/* Get the DRM device in use */
drmName = display->data->egl.queryDeviceString(display->devDpy->eglDevice,
EGL_DRM_DEVICE_FILE_EXT);
if (!drmName) {
goto fail;
}

display->drmFd = open(drmName, O_RDWR | O_CLOEXEC);
if (display->drmFd < 0) {
goto fail;
}

// The newly created WlEglDisplay has been set up properly, insert it
// in wlEglDisplayList.
Expand Down Expand Up @@ -1205,6 +1227,7 @@ EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor)
struct wl_display *wrapper = NULL;
EGLint err = EGL_SUCCESS;
int ret = 0;
const char *dev_exts = NULL;

if (!display) {
return EGL_FALSE;
Expand Down Expand Up @@ -1235,6 +1258,11 @@ EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor)
return EGL_FALSE;
}

dev_exts = display->data->egl.queryString(display->devDpy->eglDisplay, EGL_EXTENSIONS);
if (dev_exts && wlEglFindExtension("EGL_ANDROID_native_fence_sync", dev_exts)) {
display->supports_native_fence_sync = true;
}

// Set the initCount to 1. If something goes wrong, then terminateDisplay
// will clean up and set it back to zero.
display->initCount = 1;
Expand Down Expand Up @@ -1353,6 +1381,7 @@ WlEglDisplay *wlEglAcquireDisplay(EGLDisplay dpy) {
static void wlEglUnrefDisplay(WlEglDisplay *display) {
if (--display->refCount == 0) {
wlEglMutexDestroy(&display->mutex);
close(display->drmFd);
free(display);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/wayland-eglhandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver)
GET_PROC(clientWaitSync, eglClientWaitSyncKHR);
GET_PROC(signalSync, eglSignalSyncKHR);
GET_PROC(destroySync, eglDestroySyncKHR);
GET_PROC(createSync, eglCreateSyncKHR);
GET_PROC(dupNativeFenceFD, eglDupNativeFenceFDANDROID);

/* Stream flush */
GET_PROC(streamFlush, eglStreamFlushNV);
Expand Down
Loading

0 comments on commit 7a996ad

Please sign in to comment.