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 21, 2024
1 parent 369b337 commit 4f4544a
Show file tree
Hide file tree
Showing 7 changed files with 531 additions and 35 deletions.
4 changes: 4 additions & 0 deletions include/wayland-egldisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ typedef struct WlEglDisplayRec {
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 +140,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
20 changes: 20 additions & 0 deletions include/wayland-eglsurface-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ typedef struct WlEglStreamImageRec {
struct wl_buffer *buffer;
EGLBoolean attached;
struct wl_list acquiredLink;

struct wp_linux_drm_syncobj_timeline_v1 *wlReleaseTimeline;
int drmSyncobjFd;
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 +160,14 @@ 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;
int drmSyncobjFd;
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 +202,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
23 changes: 23 additions & 0 deletions 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,11 @@ registry_handle_global(void *data,
name,
&wp_presentation_interface,
version);
} else if (strcmp(interface, "wp_linux_drm_syncobj_manager_v1") == 0) {
display->wlDrmSyncobj = wl_registry_bind(registry,
name,
&wp_linux_drm_syncobj_manager_v1_interface,
version);
}
}

Expand Down Expand Up @@ -738,6 +744,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 +936,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 @@ -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);
if (display->drmFd < 0) {
goto fail;
}

// The newly created WlEglDisplay has been set up properly, insert it
// in wlEglDisplayList.
Expand Down Expand Up @@ -1353,6 +1375,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

0 comments on commit 4f4544a

Please sign in to comment.