Previously the renderers destroy function assumed they are only called
when the compositor is shutting down and that the compositor had
already destroyed all the surfaces. However, if a runtime renderer
switch would be done, the surface state would be leaked.

This patch adds a destroy_signal to the pixman and gl renderers. The
surface state objects will listen for that signal and destroy
themselves if needed.

This is a step towards runtime switchable renderers.
---
 src/gl-renderer.c     |   54 +++++++++++++++++++++++++++++++++++++++++--------
 src/pixman-renderer.c |   41 +++++++++++++++++++++++++++++++++----
 2 files changed, 83 insertions(+), 12 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index d792530..c3c6ae9 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -83,6 +83,7 @@ struct gl_surface_state {
        struct weston_surface *surface;
 
        struct wl_listener surface_destroy_listener;
+       struct wl_listener renderer_destroy_listener;
 };
 
 struct gl_renderer {
@@ -130,6 +131,8 @@ struct gl_renderer {
        struct gl_shader invert_color_shader;
        struct gl_shader solid_shader;
        struct gl_shader *current_shader;
+
+       struct wl_signal destroy_signal;
 };
 
 static inline struct gl_output_state *
@@ -1149,17 +1152,12 @@ gl_renderer_surface_set_color(struct weston_surface 
*surface,
 }
 
 static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
 {
-       struct gl_surface_state *gs;
-       struct gl_renderer *gr;
-       struct weston_surface *surface = data;
        int i;
 
-       gr = get_renderer(surface->compositor);
-
-       gs = container_of(listener, struct gl_surface_state,
-                         surface_destroy_listener);
+       wl_list_remove(&gs->surface_destroy_listener.link);
+       wl_list_remove(&gs->renderer_destroy_listener.link);
 
        gs->surface->renderer_state = NULL;
 
@@ -1173,10 +1171,39 @@ surface_state_handle_surface_destroy(struct wl_listener 
*listener, void *data)
        free(gs);
 }
 
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct gl_surface_state *gs;
+       struct gl_renderer *gr;
+
+       gs = container_of(listener, struct gl_surface_state,
+                         surface_destroy_listener);
+
+       gr = get_renderer(gs->surface->compositor);
+
+       surface_state_destroy(gs, gr);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+       struct gl_surface_state *gs;
+       struct gl_renderer *gr;
+
+       gr = data;
+
+       gs = container_of(listener, struct gl_surface_state,
+                         renderer_destroy_listener);
+
+       surface_state_destroy(gs, gr);
+}
+
 static int
 gl_renderer_create_surface(struct weston_surface *surface)
 {
        struct gl_surface_state *gs;
+       struct gl_renderer *gr = get_renderer(surface->compositor);
 
        gs = calloc(1, sizeof *gs);
        if (!gs)
@@ -1189,6 +1216,8 @@ gl_renderer_create_surface(struct weston_surface *surface)
        gs->pitch = 1;
        gs->y_inverted = 1;
 
+       gs->surface = surface;
+
        pixman_region32_init(&gs->texture_damage);
        surface->renderer_state = gs;
 
@@ -1197,6 +1226,11 @@ gl_renderer_create_surface(struct weston_surface 
*surface)
        wl_signal_add(&surface->destroy_signal,
                      &gs->surface_destroy_listener);
 
+       gs->renderer_destroy_listener.notify =
+               surface_state_handle_renderer_destroy;
+       wl_signal_add(&gr->destroy_signal,
+                     &gs->renderer_destroy_listener);
+
        return 0;
 }
 
@@ -1579,6 +1613,8 @@ gl_renderer_destroy(struct weston_compositor *ec)
 {
        struct gl_renderer *gr = get_renderer(ec);
 
+       wl_signal_emit(&gr->destroy_signal, gr);
+
        if (gr->has_bind_display)
                gr->unbind_display(gr->egl_display, ec->wl_display);
 
@@ -1705,6 +1741,8 @@ gl_renderer_create(struct weston_compositor *ec, 
EGLNativeDisplayType display,
 
        wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
 
+       wl_signal_init(&gr->destroy_signal);
+
        return 0;
 
 err_egl:
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 98a910c..79c1d5b 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -43,6 +43,7 @@ struct pixman_surface_state {
        struct weston_buffer_reference buffer_ref;
 
        struct wl_listener surface_destroy_listener;
+       struct wl_listener renderer_destroy_listener;
 };
 
 struct pixman_renderer {
@@ -51,6 +52,8 @@ struct pixman_renderer {
        int repaint_debug;
        pixman_image_t *debug_color;
        struct weston_binding *debug_binding;
+
+       struct wl_signal destroy_signal;
 };
 
 static inline struct pixman_output_state *
@@ -593,12 +596,11 @@ pixman_renderer_attach(struct weston_surface *es, struct 
weston_buffer *buffer)
 }
 
 static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
 {
-       struct pixman_surface_state *ps;
+       wl_list_remove(&ps->surface_destroy_listener.link);
+       wl_list_remove(&ps->renderer_destroy_listener.link);
 
-       ps = container_of(listener, struct pixman_surface_state,
-                         surface_destroy_listener);
 
        ps->surface->renderer_state = NULL;
 
@@ -610,10 +612,33 @@ surface_state_handle_surface_destroy(struct wl_listener 
*listener, void *data)
        free(ps);
 }
 
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct pixman_surface_state *ps;
+
+       ps = container_of(listener, struct pixman_surface_state,
+                         surface_destroy_listener);
+
+       pixman_renderer_surface_state_destroy(ps);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+       struct pixman_surface_state *ps;
+
+       ps = container_of(listener, struct pixman_surface_state,
+                         renderer_destroy_listener);
+
+       pixman_renderer_surface_state_destroy(ps);
+}
+
 static int
 pixman_renderer_create_surface(struct weston_surface *surface)
 {
        struct pixman_surface_state *ps;
+       struct pixman_renderer *pr = get_renderer(surface->compositor);
 
        ps = calloc(1, sizeof *ps);
        if (!ps)
@@ -628,6 +653,11 @@ pixman_renderer_create_surface(struct weston_surface 
*surface)
        wl_signal_add(&surface->destroy_signal,
                      &ps->surface_destroy_listener);
 
+       ps->renderer_destroy_listener.notify =
+               surface_state_handle_renderer_destroy;
+       wl_signal_add(&pr->destroy_signal,
+                     &ps->renderer_destroy_listener);
+
        return 0;
 }
 
@@ -656,6 +686,7 @@ pixman_renderer_destroy(struct weston_compositor *ec)
 {
        struct pixman_renderer *pr = get_renderer(ec);
 
+       wl_signal_emit(&pr->destroy_signal, pr);
        weston_binding_destroy(pr->debug_binding);
        free(pr);
 
@@ -710,6 +741,8 @@ pixman_renderer_init(struct weston_compositor *ec)
 
        wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
 
+       wl_signal_init(&renderer->destroy_signal);
+
        return 0;
 }
 
-- 
1.7.9.5

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to