1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
Hi,
Last month, Xan xtraced[1] cairo text drawing (using xlib), and noticed
that cairo creates (and afterward destroys) a 1x1 pixmap (a cairo
surface) every time it draws some text. Xft doesn't do this.
Carl and Behdad suggested ways to, like Xft, cache surfaces so as not to
have to recreate them all the time.
As suggested by Carl in the same thread, I first investigated
per-pattern caching of acquired surfaces. This didn't work as patterns
mostly get copied before their surfaces are requested.
Attached patch adds a simple 16-entry static cache to
_cairo_pattern_acquire_surface_for_solid(). It still needs work, however
this already yields a speedup[2] of 12% when drawing text using GTK+
2.10, exceeding the performance of GTK+ 2.6. Yay!
Comments appreciated,
Jorn
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b488d1f..be63faf 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1020,6 +1020,8 @@ _cairo_pattern_acquire_surface_for_gradi
return status;
}
+#define MAX_CACHE_SIZE 16
+
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t *dst,
@@ -1030,13 +1032,50 @@ _cairo_pattern_acquire_surface_for_solid
cairo_surface_t **out,
cairo_surface_attributes_t *attribs)
{
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- 1, 1,
- &pattern->color);
- if ((*out)->status)
+ /* We have a small cache here, because we don't want to constantly
+ * recreate surfaces for simple solid colors */
+ static struct {
+ cairo_color_t color;
+ cairo_surface_t *surface;
+ } cache[MAX_CACHE_SIZE];
+ static int cache_size = 0;
+
+ cairo_surface_t *surface;
+ int i;
+
+ /* Check cache first */
+ for (i = 0; i < cache_size; i++)
+ if (cache[i].surface->backend == dst->backend &&
+ memcmp (&cache[i].color,
+ &pattern->color,
+ sizeof (cairo_color_t)) == 0)
+ goto DONE;
+
+ /* Not cached, need to create new */
+ surface = _cairo_surface_create_similar_solid (dst,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ 1, 1,
+ &pattern->color);
+ if (surface->status)
return CAIRO_STATUS_NO_MEMORY;
+ /* Cache new */
+ if (cache_size < MAX_CACHE_SIZE)
+ cache_size++;
+ else {
+ i = random () % MAX_CACHE_SIZE;
+
+ /* Evict old */
+ cairo_surface_destroy (cache[i].surface);
+ }
+
+ cache[i].color = pattern->color;
+ cache[i].surface = surface;
+
+DONE:
+
+ *out = cairo_surface_reference (cache[i].surface);
+
attribs->x_offset = attribs->y_offset = 0;
cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
|