summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2013-11-15 13:50:49 +0000
committerKristian Høgsberg <krh@bitplanet.net>2013-12-07 22:36:02 -0800
commit25cc889004aad6d1cab9edd76db898658e347b97 (patch)
treea17ba3fa086d8ea436e92086f9584b4257032c06
parent965cde9232ca6c704ac31e924c15ddf39c58082d (diff)
wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers
Consider a typical game-style main loop which might be like this: while (1) { draw_something(); eglSwapBuffers(); } In this case the game is relying on eglSwapBuffers to throttle to a sensible frame rate. Previously this game would end up using three buffers even though it should only need two. This is because Mesa decides whether to allocate a new buffer in get_back_bo which would be before it has tried to read any events from the compositor so it wouldn't have seen any buffer release events yet. This patch just moves the block for the frame callback to get_back_bo. Typically the compositor will send a release event immediately after one of the attaches so if we block for the frame callback here then we can be sure to have completed at least one roundtrip and received that release event after attaching the previous buffer before deciding whether to allocate a new one. dri2_swap_buffers always calls get_back_bo so even if the client doesn't render anything we will still be sure to block to the frame callback. The code to create the new frame callback has been moved to after this call so that we can be sure to have cleared the previous frame callback before requesting a new one.
-rw-r--r--src/egl/drivers/dri2/platform_wayland.c36
1 files changed, 22 insertions, 14 deletions
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 443bdcaeda3..87cb718ace1 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -263,8 +263,21 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
dri2_egl_display(dri2_surf->base.Resource.Display);
int i;
- /* There might be a buffer release already queued that wasn't processed */
- wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
+ if (dri2_surf->frame_callback == NULL) {
+ /* There might be a buffer release already queued that wasn't processed
+ */
+ wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
+ } else {
+ /* We throttle to the frame callback here so that we can be sure to have
+ * received any release events before trying to decide whether to
+ * allocate a new buffer */
+ do {
+ if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
+ dri2_dpy->wl_queue) == -1)
+ return EGL_FALSE;
+ } while (dri2_surf->frame_callback != NULL);
+ }
+
if (dri2_surf->back == NULL) {
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
@@ -559,18 +572,7 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv,
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
struct dri2_egl_context *dri2_ctx;
_EGLContext *ctx;
- int i, ret = 0;
-
- while (dri2_surf->frame_callback && ret != -1)
- ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
- if (ret < 0)
- return EGL_FALSE;
-
- dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
- wl_callback_add_listener(dri2_surf->frame_callback,
- &frame_listener, dri2_surf);
- wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
- dri2_dpy->wl_queue);
+ int i;
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
if (dri2_surf->color_buffers[i].age > 0)
@@ -583,6 +585,12 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv,
return EGL_FALSE;
}
+ dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
+ wl_callback_add_listener(dri2_surf->frame_callback,
+ &frame_listener, dri2_surf);
+ wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
+ dri2_dpy->wl_queue);
+
dri2_surf->back->age = 1;
dri2_surf->current = dri2_surf->back;
dri2_surf->back = NULL;