commit d027243

Michael Forney  ·  2013-06-21 08:35:34 +0000 UTC
parent 96ab570
surface: Properly handle buffer attach and destroy
2 files changed,  +68, -18
+67, -18
  1@@ -10,9 +10,21 @@ static pixman_box32_t infinite_extents = {
  2     .x2 = INT32_MAX, .y2 = INT32_MAX
  3 };
  4 
  5+/**
  6+ * Removes a buffer from a surface state.
  7+ */
  8+static void handle_buffer_destroy(struct wl_listener * listener, void * data)
  9+{
 10+    struct swc_surface_state * state;
 11+
 12+    state = wl_container_of(listener, state, buffer_destroy_listener);
 13+    state->buffer = NULL;
 14+}
 15+
 16 static void state_initialize(struct swc_surface_state * state)
 17 {
 18     state->buffer = NULL;
 19+    state->buffer_destroy_listener.notify = &handle_buffer_destroy;
 20 
 21     pixman_region32_init(&state->damage);
 22     pixman_region32_init(&state->opaque);
 23@@ -25,6 +37,12 @@ static void state_finish(struct swc_surface_state * state)
 24 {
 25     struct wl_resource * resource, * tmp;
 26 
 27+    if (state->buffer)
 28+    {
 29+        /* Remove any buffer listeners */
 30+        wl_list_remove(&state->buffer_destroy_listener.link);
 31+    }
 32+
 33     pixman_region32_fini(&state->damage);
 34     pixman_region32_fini(&state->opaque);
 35     pixman_region32_fini(&state->input);
 36@@ -34,6 +52,37 @@ static void state_finish(struct swc_surface_state * state)
 37         wl_resource_destroy(resource);
 38 }
 39 
 40+/**
 41+ * In order to set the buffer of a surface state (current or pending), we need
 42+ * to manage the destroy listeners we have for the new and old buffer.
 43+ *
 44+ * @return: Whether or not the buffer was changed.
 45+ */
 46+static bool state_set_buffer(struct swc_surface_state * state,
 47+                             struct wl_buffer * buffer)
 48+{
 49+    if (buffer == state->buffer)
 50+        return false;
 51+
 52+    if (state->buffer)
 53+    {
 54+        /* No longer need to worry about the old buffer being destroyed. */
 55+        wl_list_remove(&state->buffer_destroy_listener.link);
 56+    }
 57+
 58+    if (buffer)
 59+    {
 60+        /* Need to watch the new buffer for destruction so we can remove it
 61+         * from state. */
 62+        wl_resource_add_destroy_listener(&buffer->resource,
 63+                                         &state->buffer_destroy_listener);
 64+    }
 65+
 66+    state->buffer = buffer;
 67+
 68+    return true;
 69+}
 70+
 71 static void destroy(struct wl_client * client, struct wl_resource * resource)
 72 {
 73     wl_resource_destroy(resource);
 74@@ -43,25 +92,17 @@ static void attach(struct wl_client * client, struct wl_resource * resource,
 75                    struct wl_resource * buffer_resource, int32_t x, int32_t y)
 76 {
 77     struct swc_surface * surface = wl_resource_get_user_data(resource);
 78+    struct wl_buffer * buffer
 79+        = buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL;
 80 
 81-    surface->pending.x = x;
 82-    surface->pending.y = y;
 83-
 84-    if (buffer_resource)
 85-    {
 86-        struct wl_buffer * buffer = wl_resource_get_user_data(buffer_resource);
 87+    state_set_buffer(&surface->pending.state, buffer);
 88 
 89-        surface->pending.state.buffer = buffer;
 90-        surface->geometry.width = buffer->width;
 91-        surface->geometry.height = buffer->height;
 92-    }
 93-    else
 94-    {
 95-        surface->pending.state.buffer = NULL;
 96+    /* Adjust geometry of the surface to match the buffer. */
 97+    surface->geometry.width = buffer ? buffer->width : 0;
 98+    surface->geometry.height = buffer ? buffer->height : 0;
 99 
100-        surface->geometry.width = 0;
101-        surface->geometry.height = 0;
102-    }
103+    surface->pending.x = x;
104+    surface->pending.y = y;
105 }
106 
107 static void damage(struct wl_client * client, struct wl_resource * resource,
108@@ -129,9 +170,17 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
109 
110     event.data = surface;
111 
112-    if (surface->pending.state.buffer != surface->state.buffer)
113+    /* Attach */
114+    if (surface->state.buffer != surface->pending.state.buffer)
115     {
116-        surface->state.buffer = surface->pending.state.buffer;
117+        if (surface->state.buffer)
118+        {
119+            /* Release the old buffer, it's no longer needed. */
120+            wl_buffer_send_release(&surface->state.buffer->resource);
121+        }
122+
123+        state_set_buffer(&surface->state, surface->pending.state.buffer);
124+
125         event.type = SWC_SURFACE_ATTACH;
126         wl_signal_emit(&surface->event_signal, &event);
127     }
+1, -0
1@@ -27,6 +27,7 @@ struct swc_surface_state
2     pixman_region32_t input;
3 
4     struct wl_list frame_callbacks;
5+    struct wl_listener buffer_destroy_listener;
6 };
7 
8 struct swc_surface