diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-11-03 12:32:04 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-11-03 13:29:34 +0100 |
commit | dc1d52bd828cb54d98769a0879c45ab53c254b01 (patch) | |
tree | 91be166339e67664bba4cc91bf3077abaeb8ef0e | |
parent | c6a302647200cb0bbc0d0d7680ad4e9fc5dd94bf (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.h | 2 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_wayland.c | 57 | ||||
-rw-r--r-- | src/gallium/state_trackers/egl/wayland/native_wayland.c | 59 | ||||
-rw-r--r-- | src/gallium/state_trackers/egl/wayland/native_wayland.h | 2 |
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; }; |