summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2011-07-08 16:51:19 +0200
committerUli Schlachter <psychon@znc.in>2011-07-09 09:42:22 +0200
commit4153de46892b47b5b21fbef8939ef732935bfe03 (patch)
treedd7fe4f15c0d81db90c90e36b30d9dbf5347814b
parente775db35d9306b74867f981a08d253562b15cffd (diff)
xcb: Track cairo_xcb_picture_t surfaces
When e.g. using an image surface as the source for a xcb surface, a cairo_xcb_picture_t is created and attached to that image surface as a snapshot. This contains the Picture that was created on the X11 server. However, as soon as the cairo_xcb_picture_t's cairo_xcb_screen_t is finished and destroyed, this picture can't be used anymore. This commit now makes sure all these Pictures are freed when the screen is finished. This was found because my X server's memory usage grew quite large. Every time the app was done drawing, it destroyed its last surface which also destroyed the last reference to the cairo_xcb_screen_t. This meant that the existing Picture snapshots couldn't be used anymore, but they were still kept around and used up memory until there wasn't any free memory left. Signed-off-by: Uli Schlachter <psychon@znc.in>
-rw-r--r--src/cairo-xcb-private.h3
-rw-r--r--src/cairo-xcb-screen.c13
-rw-r--r--src/cairo-xcb-surface-render.c3
3 files changed, 19 insertions, 0 deletions
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 82e05c3c..3f085e0d 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -123,6 +123,8 @@ struct _cairo_xcb_picture {
int x0, y0;
int x, y;
+
+ cairo_list_t link;
};
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
@@ -189,6 +191,7 @@ struct _cairo_xcb_screen {
cairo_list_t link;
cairo_list_t surfaces;
+ cairo_list_t pictures;
};
struct _cairo_xcb_connection {
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
index b61f20b7..efe42cf9 100644
--- a/src/cairo-xcb-screen.c
+++ b/src/cairo-xcb-screen.c
@@ -62,6 +62,18 @@ _cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
cairo_surface_destroy (surface);
}
+ while (! cairo_list_is_empty (&screen->pictures)) {
+ cairo_surface_t *surface;
+
+ surface = &cairo_list_first_entry (&screen->pictures,
+ cairo_xcb_picture_t,
+ link)->base;
+
+ cairo_surface_reference (surface);
+ cairo_surface_finish (surface);
+ cairo_surface_destroy (surface);
+ }
+
for (i = 0; i < screen->solid_cache_size; i++)
cairo_surface_destroy (screen->solid_cache[i].picture);
@@ -231,6 +243,7 @@ _cairo_xcb_screen_get (xcb_connection_t *xcb_connection,
sizeof (struct pattern_cache_entry));
cairo_list_init (&screen->link);
cairo_list_init (&screen->surfaces);
+ cairo_list_init (&screen->pictures);
if (connection->flags & CAIRO_XCB_HAS_DRI2)
screen->device = _xcb_drm_device (xcb_connection, xcb_screen);
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 0c31820c..e8d6c52d 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -85,6 +85,7 @@ _cairo_xcb_picture_finish (void *abstract_surface)
cairo_status_t status;
status = _cairo_xcb_connection_acquire (connection);
+ cairo_list_del (&surface->link);
if (unlikely (status))
return status;
@@ -125,6 +126,8 @@ _cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
&screen->connection->device,
_cairo_content_from_pixman_format (pixman_format));
+ cairo_list_add (&surface->link, &screen->pictures);
+
surface->screen = screen;
surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
surface->pixman_format = pixman_format;