[PATCH] Disable the client's event queue when there are no frame callbacks

Neil Roberts neil at linux.intel.com
Fri Sep 13 08:13:23 PDT 2013


Weston now keeps track of the number of frame callbacks that are
installed for a particular client using some data attached in the
destroy listener of the wl_client. Whenever this number reaches zero,
it will disable the client's event queue using the new
wl_client_disable_queue API. That way if the client isn't using frame
callbacks it can get buffer release events immediately. Without this
the client may never get the buffer release events because nothing
else will post an event to the client.
---
 src/compositor.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 2 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 8c9e0fe..566f0bf 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -998,6 +998,7 @@ weston_surface_unmap(struct weston_surface *surface)
 struct weston_frame_callback {
 	struct wl_resource *resource;
 	struct wl_list link;
+	int committed;
 };
 
 
@@ -1478,11 +1479,65 @@ surface_damage(struct wl_client *client,
 				   x, y, width, height);
 }
 
+struct weston_client_data {
+	struct wl_listener listener;
+	int n_pending_frame_callbacks;
+};
+
+static void
+destroy_client_data(struct wl_listener *listener, void *data)
+{
+	struct weston_client_data *client_data =
+		container_of(listener,
+			     struct weston_client_data,
+			     listener);
+
+	free(client_data);
+}
+
+static struct weston_client_data *
+weston_get_client_data(struct wl_client *client,
+		       int create)
+{
+	struct weston_client_data *data;
+	struct wl_listener *listener;
+
+	listener = wl_client_get_destroy_listener(client, destroy_client_data);
+	if (listener) {
+		return container_of(listener,
+				    struct weston_client_data,
+				    listener);
+	}
+
+	if (!create)
+		return NULL;
+
+	data = malloc(sizeof(struct weston_client_data));
+	if (!data)
+		return NULL;
+
+	data->n_pending_frame_callbacks = 0;
+	data->listener.notify = destroy_client_data;
+	wl_client_add_destroy_listener(client, &data->listener);
+
+	return data;
+}
+
 static void
 destroy_frame_callback(struct wl_resource *resource)
 {
 	struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
 
+	if (cb->committed) {
+		struct wl_client *client = wl_resource_get_client(resource);
+		struct weston_client_data *client_data =
+			weston_get_client_data(client, 0 /* no create */);
+
+		if (client_data &&
+		    --client_data->n_pending_frame_callbacks < 1)
+			wl_client_disable_queue(client);
+	}
+
 	wl_list_remove(&cb->link);
 	free(cb);
 }
@@ -1562,6 +1617,36 @@ weston_surface_commit_subsurface_order(struct weston_surface *surface)
 }
 
 static void
+add_frame_callbacks(struct weston_surface *surface,
+		    struct wl_list *callbacks)
+{
+	struct weston_frame_callback *cb;
+	int count = 0;
+
+	wl_list_for_each(cb, callbacks, link) {
+		cb->committed = 1;
+		count++;
+	}
+
+	if (count > 0) {
+		struct wl_client *client =
+			wl_resource_get_client(surface->resource);
+		struct weston_client_data *client_data =
+			weston_get_client_data(client, 1 /* create */);
+
+		if (client_data) {
+			/* The client queue will be enabled only while
+			 * there are pending frame callbacks */
+			if (client_data->n_pending_frame_callbacks == 0)
+				wl_client_enable_queue(client);
+			client_data->n_pending_frame_callbacks += count;
+		}
+
+		wl_list_insert_list(&surface->frame_callback_list, callbacks);
+	}
+}
+
+static void
 weston_surface_commit(struct weston_surface *surface)
 {
 	pixman_region32_t opaque;
@@ -1627,8 +1712,7 @@ weston_surface_commit(struct weston_surface *surface)
 				  &surface->input, &surface->pending.input);
 
 	/* wl_surface.frame */
-	wl_list_insert_list(&surface->frame_callback_list,
-			    &surface->pending.frame_callback_list);
+	add_frame_callbacks(surface, &surface->pending.frame_callback_list);
 	wl_list_init(&surface->pending.frame_callback_list);
 
 	weston_surface_commit_subsurface_order(surface);
@@ -2840,6 +2924,10 @@ compositor_bind(struct wl_client *client,
 	struct weston_compositor *compositor = data;
 	struct wl_resource *resource;
 
+	/* We only want the client's queue to be enabled while it has
+	 * a frame callback */
+	wl_client_disable_queue(client);
+
 	resource = wl_resource_create(client, &wl_compositor_interface,
 				      MIN(version, 3), id);
 	if (resource == NULL) {
-- 
1.8.3.1



More information about the wayland-devel mailing list