summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2011-11-03 12:32:04 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2011-11-03 13:29:34 +0100
commitdc1d52bd828cb54d98769a0879c45ab53c254b01 (patch)
tree91be166339e67664bba4cc91bf3077abaeb8ef0e
parentc6a302647200cb0bbc0d0d7680ad4e9fc5dd94bf (diff)
egl/wayland: Use frame_fd synchronization requestframefd
This removes the wayland event dispatcher, that used to wait for the frame event, and as a consequence dispatched all wayland events, even egl unrelated events. This gave problems when eglSwapBuffers was called from another thread than the users event dispatcher. wl_surface_frame_fd signals the frame event using a pipe.
-rw-r--r--src/egl/drivers/dri2/egl_dri2.h2
-rw-r--r--src/egl/drivers/dri2/platform_wayland.c57
-rw-r--r--src/gallium/state_trackers/egl/wayland/native_wayland.c59
-rw-r--r--src/gallium/state_trackers/egl/wayland/native_wayland.h2
4 files changed, 77 insertions, 43 deletions
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 1c2c7fe5a6..8f6b0b57ac 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -162,7 +162,7 @@ struct dri2_egl_surface
__DRIbuffer *dri_buffers[__DRI_BUFFER_COUNT];
__DRIbuffer *third_buffer;
__DRIbuffer *pending_buffer;
- EGLBoolean block_swap_buffers;
+ int framefd[2];
int format;
#endif
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 7a70d8d590..86157c337c 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -105,7 +105,7 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
dri2_surf->pending_buffer = NULL;
dri2_surf->third_buffer = NULL;
- dri2_surf->block_swap_buffers = EGL_FALSE;
+ dri2_surf->framefd[0] = dri2_surf->framefd[1] = -1;
if (conf->AlphaSize == 0)
dri2_surf->format = WL_DRM_FORMAT_XRGB32;
@@ -195,6 +195,10 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
+ for (i = 0; i < 2; ++i)
+ if (dri2_surf->framefd[i] != -1)
+ close(dri2_surf->framefd[i]);
+
for (i = 0; i < WL_BUFFER_COUNT; ++i)
if (dri2_surf->wl_drm_buffer[i])
wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
@@ -550,18 +554,35 @@ dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
#endif
}
-static void
-wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+static EGLBoolean
+synchronize_to_frame(struct dri2_egl_surface *dri2_surf)
{
- struct dri2_egl_surface *dri2_surf = data;
+ int ret;
+ uint32_t time;
+
+ if (dri2_surf->framefd[0] != -1) {
+ /* Block for server sync. */
+ do {
+ ret = read(dri2_surf->framefd[0], &time, sizeof time);
+ } while (ret < 0 && errno == EINTR);
+ close(dri2_surf->framefd[0]);
+ dri2_surf->framefd[0] = -1;
+ }
- dri2_surf->block_swap_buffers = EGL_FALSE;
- wl_callback_destroy(callback);
-}
+ /* Prepare for next frame. */
+ ret = pipe2(dri2_surf->framefd, O_CLOEXEC);
+ if (ret == -1) {
+ _eglLog(_EGL_WARNING, "Failed to create frame synchronization pipe: %s",
+ strerror(errno));
+ return EGL_FALSE;
+ }
-static const struct wl_callback_listener frame_listener = {
- wayland_frame_callback
-};
+ wl_surface_frame_fd(dri2_surf->wl_win->surface, dri2_surf->framefd[1]);
+ close(dri2_surf->framefd[1]);
+ dri2_surf->framefd[1] = -1;
+
+ return EGL_TRUE;
+}
/**
* Called via eglSwapBuffers(), drv->API.SwapBuffers().
@@ -572,19 +593,9 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
- struct wl_callback *callback;
-
- if (dri2_surf->block_swap_buffers) {
- wl_display_flush(dri2_dpy->wl_dpy);
- while (dri2_surf->block_swap_buffers)
- wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE);
- }
-
- dri2_surf->block_swap_buffers = EGL_TRUE;
- callback = wl_surface_frame(dri2_surf->wl_win->surface);
- wl_callback_add_listener(callback, &frame_listener, dri2_surf);
if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
+ synchronize_to_frame(dri2_surf);
pointer_swap(
(const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
(const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
@@ -616,6 +627,10 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
dri2_surf->base.Width, dri2_surf->base.Height);
+
+ /* Ensure wl_surface_frame_fd is send to server before
+ * we block in next swap_buffers. */
+ wl_display_flush(dri2_dpy->wl_dpy);
}
_EGLContext *ctx;
diff --git a/src/gallium/state_trackers/egl/wayland/native_wayland.c b/src/gallium/state_trackers/egl/wayland/native_wayland.c
index c6942931ec..63f0e566dc 100644
--- a/src/gallium/state_trackers/egl/wayland/native_wayland.c
+++ b/src/gallium/state_trackers/egl/wayland/native_wayland.c
@@ -32,6 +32,9 @@
#include "pipe/p_state.h"
#include "state_tracker/drm_driver.h"
#include "egllog.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
#include "native_wayland.h"
@@ -247,20 +250,36 @@ wayland_surface_validate(struct native_surface *nsurf, uint attachment_mask,
return TRUE;
}
-static void
-wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+static boolean
+wayland_synchronize_to_frame(struct wayland_surface *surface)
{
- struct wayland_surface *surface = data;
-
- surface->block_swap_buffers = FALSE;
+ int ret;
+ uint32_t time;
+
+ if (surface->framefd[0] != -1) {
+ /* Block for server sync. */
+ do {
+ ret = read(surface->framefd[0], &time, sizeof time);
+ } while (ret < 0 && errno == EINTR);
+ close(surface->framefd[0]);
+ surface->framefd[0] = -1;
+ }
+
+ /* Prepare for next frame. */
+ ret = pipe2(surface->framefd, O_CLOEXEC);
+ if (ret == -1) {
+ _eglLog(_EGL_WARNING, "Failed to create frame synchronization pipe: %s",
+ strerror(errno));
+ return FALSE;
+ }
+
+ wl_surface_frame_fd(surface->win->surface, surface->framefd[1]);
+ close(surface->framefd[1]);
+ surface->framefd[1] = -1;
- wl_callback_destroy(callback);
+ return TRUE;
}
-static const struct wl_callback_listener frame_listener = {
- wayland_frame_callback
-};
-
static INLINE void
wayland_buffers_swap(struct wl_buffer **buffer,
enum wayland_buffer_type buf1,
@@ -276,17 +295,9 @@ wayland_surface_swap_buffers(struct native_surface *nsurf)
{
struct wayland_surface *surface = wayland_surface(nsurf);
struct wayland_display *display = surface->display;
- struct wl_callback *callback;
-
- while (surface->block_swap_buffers)
- wl_display_iterate(display->dpy, WL_DISPLAY_READABLE);
-
- surface->block_swap_buffers = TRUE;
-
- callback = wl_surface_frame(surface->win->surface);
- wl_callback_add_listener(callback, &frame_listener, surface);
if (surface->type == WL_WINDOW_SURFACE) {
+ wayland_synchronize_to_frame(surface);
resource_surface_swap_buffers(surface->rsurf,
NATIVE_ATTACHMENT_FRONT_LEFT,
NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
@@ -357,6 +368,8 @@ wayland_surface_present(struct native_surface *nsurf,
resource_surface_get_size(surface->rsurf, &width, &height);
wl_buffer_damage(surface->buffer[WL_BUFFER_FRONT], 0, 0, width, height);
wl_surface_damage(surface->win->surface, 0, 0, width, height);
+ /* Need to flush to ensure frame_fd is send before next swap_buffers. */
+ wl_display_flush(surface->display->dpy);
}
return ret;
@@ -373,12 +386,17 @@ wayland_surface_destroy(struct native_surface *nsurf)
{
struct wayland_surface *surface = wayland_surface(nsurf);
enum wayland_buffer_type buffer;
+ int i;
for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
if (surface->buffer[buffer])
wl_buffer_destroy(surface->buffer[buffer]);
}
+ for (i = 0; i < 2; ++i)
+ if (surface->framefd[i] != 1)
+ close(surface->framefd[i]);
+
resource_surface_destroy(surface->rsurf);
FREE(surface);
}
@@ -404,6 +422,7 @@ wayland_create_pixmap_surface(struct native_display *ndpy,
surface->display = display;
surface->pending_resource = NULL;
+ surface->framefd[0] = surface->framefd[1] = -1;
surface->type = WL_PIXMAP_SURFACE;
surface->pix = egl_pixmap;
@@ -460,7 +479,7 @@ wayland_create_window_surface(struct native_display *ndpy,
surface->win = (struct wl_egl_window *) win;
surface->pending_resource = NULL;
- surface->block_swap_buffers = FALSE;
+ surface->framefd[0] = surface->framefd[1] = -1;
surface->type = WL_WINDOW_SURFACE;
surface->buffer[WL_BUFFER_FRONT] = NULL;
diff --git a/src/gallium/state_trackers/egl/wayland/native_wayland.h b/src/gallium/state_trackers/egl/wayland/native_wayland.h
index 143428c5f9..6da9133b00 100644
--- a/src/gallium/state_trackers/egl/wayland/native_wayland.h
+++ b/src/gallium/state_trackers/egl/wayland/native_wayland.h
@@ -86,7 +86,7 @@ struct wayland_surface {
struct wl_buffer *buffer[WL_BUFFER_COUNT];
unsigned int attachment_mask;
- boolean block_swap_buffers;
+ int framefd[2];
boolean premultiplied_alpha;
};