Commit a95bb6f7 authored by Alexandros Frantzis's avatar Alexandros Frantzis Committed by Pekka Paalanen

clients: Support explicit synchronization in simple-dmabuf-egl

Signed-off-by: Alexandros Frantzis's avatarAlexandros Frantzis <alexandros.frantzis@collabora.com>

Changes in v7:
  - Merge acquire fence and release fence code blocks in redraw().
  - Use 1 << n to define option bitflags.
  - Remove redundant statement involving OPT_IMPLICIT_SYNC.

Changes in v6:
  - Add option for window size.
  - Add option for enabling/disabling explicit sync.

Changes in v5:
  - Meson support.
parent c715c750
......@@ -698,7 +698,9 @@ nodist_weston_simple_dmabuf_egl_SOURCES = \
protocol/fullscreen-shell-unstable-v1-protocol.c \
protocol/fullscreen-shell-unstable-v1-client-protocol.h \
protocol/linux-dmabuf-unstable-v1-protocol.c \
protocol/linux-dmabuf-unstable-v1-client-protocol.h
protocol/linux-dmabuf-unstable-v1-client-protocol.h \
protocol/linux-explicit-synchronization-unstable-v1-protocol.c \
protocol/linux-explicit-synchronization-v1-client-protocol.h
weston_simple_dmabuf_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_DMABUF_EGL_CLIENT_CFLAGS)
weston_simple_dmabuf_egl_LDADD = $(SIMPLE_DMABUF_EGL_CLIENT_LIBS) libshared.la -lm
endif
......
......@@ -54,6 +54,8 @@ simple_clients = [
'simple-dmabuf-egl.c',
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
linux_explicit_synchronization_unstable_v1_client_protocol_h,
linux_explicit_synchronization_unstable_v1_protocol_c,
xdg_shell_unstable_v6_client_protocol_h,
xdg_shell_unstable_v6_protocol_c,
fullscreen_shell_unstable_v1_client_protocol_h,
......
......@@ -50,6 +50,7 @@
#include "xdg-shell-unstable-v6-client-protocol.h"
#include "fullscreen-shell-unstable-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-explicit-synchronization-unstable-v1-client-protocol.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
......@@ -63,7 +64,8 @@
#endif
/* Possible options that affect the displayed image */
#define OPT_IMMEDIATE 1 /* create wl_buffer immediately */
#define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
#define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
#define BUFFER_FORMAT DRM_FORMAT_XRGB8888
#define MAX_BUFFER_PLANES 4
......@@ -75,9 +77,11 @@ struct display {
struct zxdg_shell_v6 *shell;
struct zwp_fullscreen_shell_v1 *fshell;
struct zwp_linux_dmabuf_v1 *dmabuf;
struct zwp_linux_explicit_synchronization_v1 *explicit_sync;
uint64_t *modifiers;
int modifiers_count;
int req_dmabuf_immediate;
bool use_explicit_sync;
struct {
EGLDisplay display;
EGLContext context;
......@@ -86,6 +90,11 @@ struct display {
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
PFNEGLCREATESYNCKHRPROC create_sync;
PFNEGLDESTROYSYNCKHRPROC destroy_sync;
PFNEGLCLIENTWAITSYNCKHRPROC client_wait_sync;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC dup_native_fence_fd;
PFNEGLWAITSYNCKHRPROC wait_sync;
} egl;
struct {
int drm_fd;
......@@ -112,6 +121,11 @@ struct buffer {
EGLImageKHR egl_image;
GLuint gl_texture;
GLuint gl_fbo;
struct zwp_linux_buffer_release_v1 *buffer_release;
/* The buffer owns the release_fence_fd, until it passes ownership
* to it to EGL (see wait_for_buffer_release_fence). */
int release_fence_fd;
};
#define NUM_BUFFERS 3
......@@ -122,6 +136,7 @@ struct window {
struct wl_surface *surface;
struct zxdg_surface_v6 *xdg_surface;
struct zxdg_toplevel_v6 *xdg_toplevel;
struct zwp_linux_surface_synchronization_v1 *surface_sync;
struct buffer buffers[NUM_BUFFERS];
struct wl_callback *callback;
bool initialized;
......@@ -156,6 +171,12 @@ buffer_free(struct buffer *buf)
{
int i;
if (buf->release_fence_fd >= 0)
close(buf->release_fence_fd);
if (buf->buffer_release)
zwp_linux_buffer_release_v1_destroy(buf->buffer_release);
if (buf->gl_fbo)
glDeleteFramebuffers(1, &buf->gl_fbo);
......@@ -187,7 +208,13 @@ create_succeeded(void *data,
struct buffer *buffer = data;
buffer->buffer = new_buffer;
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
/* When not using explicit synchronization listen to wl_buffer.release
* for release notifications, otherwise we are going to use
* zwp_linux_buffer_release_v1. */
if (!buffer->display->use_explicit_sync) {
wl_buffer_add_listener(buffer->buffer, &buffer_listener,
buffer);
}
zwp_linux_buffer_params_v1_destroy(params);
}
......@@ -308,6 +335,7 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
buffer->width = width;
buffer->height = height;
buffer->format = BUFFER_FORMAT;
buffer->release_fence_fd = -1;
#ifdef HAVE_GBM_MODIFIERS
if (display->modifiers_count > 0) {
......@@ -378,7 +406,14 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
buffer->height,
buffer->format,
flags);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
/* When not using explicit synchronization listen to
* wl_buffer.release for release notifications, otherwise we
* are going to use zwp_linux_buffer_release_v1. */
if (!buffer->display->use_explicit_sync) {
wl_buffer_add_listener(buffer->buffer,
&buffer_listener,
buffer);
}
}
else {
zwp_linux_buffer_params_v1_create(params,
......@@ -540,6 +575,8 @@ destroy_window(struct window *window)
zxdg_toplevel_v6_destroy(window->xdg_toplevel);
if (window->xdg_surface)
zxdg_surface_v6_destroy(window->xdg_surface);
if (window->surface_sync)
zwp_linux_surface_synchronization_v1_destroy(window->surface_sync);
wl_surface_destroy(window->surface);
free(window);
}
......@@ -592,6 +629,13 @@ create_window(struct display *display, int width, int height)
assert(0);
}
if (display->explicit_sync) {
window->surface_sync =
zwp_linux_explicit_synchronization_v1_get_synchronization(
display->explicit_sync, window->surface);
assert(window->surface_sync);
}
for (i = 0; i < NUM_BUFFERS; ++i) {
int j;
for (j = 0; j < MAX_BUFFER_PLANES; ++j)
......@@ -619,6 +663,26 @@ error:
return NULL;
}
static int
create_egl_fence_fd(struct window *window)
{
struct display *d = window->display;
EGLSyncKHR sync = d->egl.create_sync(d->egl.display,
EGL_SYNC_NATIVE_FENCE_ANDROID,
NULL);
int fd;
assert(sync != EGL_NO_SYNC_KHR);
/* We need to flush before we can get the fence fd. */
glFlush();
fd = d->egl.dup_native_fence_fd(d->egl.display, sync);
assert(fd >= 0);
d->egl.destroy_sync(d->egl.display, sync);
return fd;
}
static struct buffer *
window_next_buffer(struct window *window)
{
......@@ -691,6 +755,70 @@ render(struct window *window, struct buffer *buffer)
glDisableVertexAttribArray(window->gl.color);
}
static void
buffer_fenced_release(void *data,
struct zwp_linux_buffer_release_v1 *release,
int32_t fence)
{
struct buffer *buffer = data;
assert(release == buffer->buffer_release);
assert(buffer->release_fence_fd == -1);
buffer->busy = 0;
buffer->release_fence_fd = fence;
zwp_linux_buffer_release_v1_destroy(buffer->buffer_release);
buffer->buffer_release = NULL;
}
static void
buffer_immediate_release(void *data,
struct zwp_linux_buffer_release_v1 *release)
{
struct buffer *buffer = data;
assert(release == buffer->buffer_release);
assert(buffer->release_fence_fd == -1);
buffer->busy = 0;
zwp_linux_buffer_release_v1_destroy(buffer->buffer_release);
buffer->buffer_release = NULL;
}
static const struct zwp_linux_buffer_release_v1_listener buffer_release_listener = {
buffer_fenced_release,
buffer_immediate_release,
};
static void
wait_for_buffer_release_fence(struct buffer *buffer)
{
struct display *d = buffer->display;
EGLint attrib_list[] = {
EGL_SYNC_NATIVE_FENCE_FD_ANDROID, buffer->release_fence_fd,
EGL_NONE,
};
EGLSyncKHR sync = d->egl.create_sync(d->egl.display,
EGL_SYNC_NATIVE_FENCE_ANDROID,
attrib_list);
int ret;
assert(sync);
/* EGLSyncKHR takes ownership of the fence fd. */
buffer->release_fence_fd = -1;
if (d->egl.wait_sync)
ret = d->egl.wait_sync(d->egl.display, sync, 0);
else
ret = d->egl.client_wait_sync(d->egl.display, sync, 0,
EGL_FOREVER_KHR);
assert(ret == EGL_TRUE);
ret = d->egl.destroy_sync(d->egl.display, sync);
assert(ret == EGL_TRUE);
}
static void
redraw(void *data, struct wl_callback *callback, uint32_t time)
{
......@@ -705,8 +833,24 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
abort();
}
if (buffer->release_fence_fd >= 0)
wait_for_buffer_release_fence(buffer);
render(window, buffer);
glFinish();
if (window->display->use_explicit_sync) {
int fence_fd = create_egl_fence_fd(window);
zwp_linux_surface_synchronization_v1_set_acquire_fence(
window->surface_sync, fence_fd);
close(fence_fd);
buffer->buffer_release =
zwp_linux_surface_synchronization_v1_get_release(window->surface_sync);
zwp_linux_buffer_release_v1_add_listener(
buffer->buffer_release, &buffer_release_listener, buffer);
} else {
glFinish();
}
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
......@@ -787,6 +931,10 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->dmabuf = wl_registry_bind(registry,
id, &zwp_linux_dmabuf_v1_interface, 3);
zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
} else if (strcmp(interface, "zwp_linux_explicit_synchronization_v1") == 0) {
d->explicit_sync = wl_registry_bind(
registry, id,
&zwp_linux_explicit_synchronization_v1_interface, 1);
}
}
......@@ -932,6 +1080,33 @@ display_set_up_egl(struct display *display)
(void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
assert(display->egl.image_target_texture_2d);
if (weston_check_egl_extension(egl_extensions, "EGL_KHR_fence_sync") &&
weston_check_egl_extension(egl_extensions,
"EGL_ANDROID_native_fence_sync")) {
display->egl.create_sync =
(void *) eglGetProcAddress("eglCreateSyncKHR");
assert(display->egl.create_sync);
display->egl.destroy_sync =
(void *) eglGetProcAddress("eglDestroySyncKHR");
assert(display->egl.destroy_sync);
display->egl.client_wait_sync =
(void *) eglGetProcAddress("eglClientWaitSyncKHR");
assert(display->egl.client_wait_sync);
display->egl.dup_native_fence_fd =
(void *) eglGetProcAddress("eglDupNativeFenceFDANDROID");
assert(display->egl.dup_native_fence_fd);
}
if (weston_check_egl_extension(egl_extensions,
"EGL_KHR_wait_sync")) {
display->egl.wait_sync =
(void *) eglGetProcAddress("eglWaitSyncKHR");
assert(display->egl.wait_sync);
}
return true;
error:
......@@ -1070,6 +1245,29 @@ create_display(char const *drm_render_node, int opts)
if (!display_set_up_gbm(display, drm_render_node))
goto error;
/* We use explicit synchronization only if the user hasn't disabled it,
* the compositor supports it, we can handle fence fds. */
display->use_explicit_sync =
!(opts & OPT_IMPLICIT_SYNC) &&
display->explicit_sync &&
display->egl.dup_native_fence_fd;
if (opts & OPT_IMPLICIT_SYNC) {
fprintf(stderr, "Warning: Not using explicit sync, disabled by user\n");
} else if (!display->explicit_sync) {
fprintf(stderr,
"Warning: zwp_linux_explicit_synchronization_v1 not supported,\n"
" will not use explicit synchronization\n");
} else if (!display->egl.dup_native_fence_fd) {
fprintf(stderr,
"Warning: EGL_ANDROID_native_fence_sync not supported,\n"
" will not use explicit synchronization\n");
} else if (!display->egl.wait_sync) {
fprintf(stderr,
"Warning: EGL_KHR_wait_sync not supported,\n"
" will not use server-side wait\n");
}
return display;
error:
......@@ -1092,7 +1290,12 @@ print_usage_and_exit(void)
"\n\t\t0 to import dmabuf via roundtrip, "
"\n\t\t1 to enable import without roundtrip\n"
"\t'-d,--drm-render-node=<>'"
"\n\t\tthe full path to the drm render node to use\n");
"\n\t\tthe full path to the drm render node to use\n"
"\t'-s,--size=<>'"
"\n\t\tthe window size in pixels (default: 256)\n"
"\t'-e,--explicit-sync=<>'"
"\n\t\t0 to disable explicit sync, "
"\n\t\t1 to enable explicit sync (default: 1)\n");
exit(0);
}
......@@ -1118,15 +1321,18 @@ main(int argc, char **argv)
int opts = 0;
char const *drm_render_node = "/dev/dri/renderD128";
int c, option_index, ret = 0;
int window_size = 256;
static struct option long_options[] = {
{"import-immediate", required_argument, 0, 'i' },
{"drm-render-node", required_argument, 0, 'd' },
{"size", required_argument, 0, 's' },
{"explicit-sync", required_argument, 0, 'e' },
{"help", no_argument , 0, 'h' },
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "hi:d:",
while ((c = getopt_long(argc, argv, "hi:d:s:e:",
long_options, &option_index)) != -1) {
switch (c) {
case 'i':
......@@ -1136,6 +1342,13 @@ main(int argc, char **argv)
case 'd':
drm_render_node = optarg;
break;
case 's':
window_size = strtol(optarg, NULL, 10);
break;
case 'e':
if (!is_true(optarg))
opts |= OPT_IMPLICIT_SYNC;
break;
default:
print_usage_and_exit();
}
......@@ -1144,7 +1357,7 @@ main(int argc, char **argv)
display = create_display(drm_render_node, opts);
if (!display)
return 1;
window = create_window(display, 256, 256);
window = create_window(display, window_size, window_size);
if (!window)
return 1;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment