[cairo] Cache freed gstates.

Reduce the malloc pressure from frequent cairo_save()/cairo_restore() by
caching the freed gstates in a list on the context.
This commit is contained in:
Chris Wilson 2008-04-29 11:56:21 +01:00
parent c57b1eca18
commit b2eadb94f8
4 changed files with 35 additions and 57 deletions

View file

@ -204,47 +204,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
gstate->source = NULL;
}
static void
_cairo_gstate_destroy (cairo_gstate_t *gstate)
{
_cairo_gstate_fini (gstate);
free (gstate);
}
/**
* _cairo_gstate_clone:
* @other: a #cairo_gstate_t to be copied, not %NULL.
*
* Create a new #cairo_gstate_t setting all graphics state parameters
* to the same values as contained in @other. gstate->next will be set
* to %NULL and may be used by the caller to chain #cairo_gstate_t
* objects together.
*
* Return value: a new #cairo_gstate_t or %NULL if there is insufficient
* memory.
**/
static cairo_status_t
_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
{
cairo_status_t status;
cairo_gstate_t *gstate;
assert (other != NULL);
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_gstate_init_copy (gstate, other);
if (status) {
free (gstate);
return status;
}
*out = gstate;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_gstate_save:
* @gstate: input/output gstate pointer
@ -254,14 +213,25 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
* copy into @gstate. _cairo_gstate_restore() reverses this.
**/
cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate)
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top = NULL;
cairo_gstate_t *top;
cairo_status_t status;
status = _cairo_gstate_clone (*gstate, &top);
if (status)
top = *freelist;
if (top == NULL) {
top = malloc (sizeof (cairo_gstate_t));
if (top == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else
*freelist = top->next;
status = _cairo_gstate_init_copy (top, *gstate);
if (status) {
top->next = *freelist;
*freelist = top;
return status;
}
top->next = *gstate;
*gstate = top;
@ -276,7 +246,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate)
* Reverses the effects of one _cairo_gstate_save() call.
**/
cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate)
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top;
@ -286,7 +256,9 @@ _cairo_gstate_restore (cairo_gstate_t **gstate)
*gstate = top->next;
_cairo_gstate_destroy (top);
_cairo_gstate_fini (top);
top->next = *freelist;
*freelist = top;
return CAIRO_STATUS_SUCCESS;
}

View file

@ -49,6 +49,7 @@ struct _cairo {
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[1];
cairo_gstate_t *gstate_freelist;
cairo_path_fixed_t path[1];
};

View file

@ -52,7 +52,8 @@ static const cairo_t _cairo_nil = {
{{ /* gstate_tail */
0
}},
{{ /* path */
NULL, /* gstate_freelist */
{{ /* path */
{ 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */
FALSE, /* has_current_point */
@ -205,6 +206,7 @@ cairo_create (cairo_surface_t *target)
_cairo_path_fixed_init (cr->path);
cr->gstate = cr->gstate_tail;
cr->gstate_freelist = NULL;
status = _cairo_gstate_init (cr->gstate, target);
if (status)
@ -260,11 +262,16 @@ cairo_destroy (cairo_t *cr)
return;
while (cr->gstate != cr->gstate_tail) {
if (_cairo_gstate_restore (&cr->gstate))
if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist))
break;
}
_cairo_gstate_fini (cr->gstate);
while (cr->gstate_freelist != NULL) {
cairo_gstate_t *gstate = cr->gstate_freelist;
cr->gstate_freelist = gstate->next;
free (gstate);
}
_cairo_path_fixed_fini (cr->path);
@ -371,10 +378,9 @@ cairo_save (cairo_t *cr)
if (cr->status)
return;
status = _cairo_gstate_save (&cr->gstate);
if (status) {
status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
if (status)
_cairo_set_error (cr, status);
}
}
slim_hidden_def(cairo_save);
@ -394,10 +400,9 @@ cairo_restore (cairo_t *cr)
if (cr->status)
return;
status = _cairo_gstate_restore (&cr->gstate);
if (status) {
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
if (status)
_cairo_set_error (cr, status);
}
}
slim_hidden_def(cairo_restore);

4
src/cairoint.h Executable file → Normal file
View file

@ -952,10 +952,10 @@ cairo_private void
_cairo_gstate_fini (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate);
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
cairo_private cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate);
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
cairo_private cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate);