mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-13 10:50:28 +01:00
recording: Perform an explicit during snapshot
In order to avoid recursing upon our source mutex when doing a snapshot, we can perform an explicit copy of the command array. This should also be faster than performing a replay as well. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50443 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
797441093a
commit
8020e0bc8c
1 changed files with 311 additions and 1 deletions
|
|
@ -1088,6 +1088,316 @@ CLEANUP_COMPOSITE:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
_command_init_copy (cairo_recording_surface_t *surface,
|
||||
cairo_command_header_t *dst,
|
||||
const cairo_command_header_t *src)
|
||||
{
|
||||
dst->type = src->type;
|
||||
dst->op = src->op;
|
||||
dst->region = CAIRO_RECORDING_REGION_ALL;
|
||||
|
||||
dst->extents = src->extents;
|
||||
dst->chain = NULL;
|
||||
dst->index = surface->commands.num_elements;
|
||||
|
||||
dst->clip = _cairo_clip_copy (src->clip);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy__paint (cairo_recording_surface_t *surface,
|
||||
const cairo_command_t *src)
|
||||
{
|
||||
cairo_command_paint_t *command;
|
||||
cairo_status_t status;
|
||||
|
||||
command = malloc (sizeof (*command));
|
||||
if (unlikely (command == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
_command_init_copy (surface, &command->header, &src->header);
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->source.base,
|
||||
&src->paint.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_command;
|
||||
|
||||
status = _cairo_recording_surface_commit (surface, &command->header);
|
||||
if (unlikely (status))
|
||||
goto err_source;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
err_source:
|
||||
_cairo_pattern_fini (&command->source.base);
|
||||
err_command:
|
||||
free(command);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy__mask (cairo_recording_surface_t *surface,
|
||||
const cairo_command_t *src)
|
||||
{
|
||||
cairo_command_mask_t *command;
|
||||
cairo_status_t status;
|
||||
|
||||
command = malloc (sizeof (*command));
|
||||
if (unlikely (command == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
_command_init_copy (surface, &command->header, &src->header);
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->source.base,
|
||||
&src->mask.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_command;
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->mask.base,
|
||||
&src->mask.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_source;
|
||||
|
||||
status = _cairo_recording_surface_commit (surface, &command->header);
|
||||
if (unlikely (status))
|
||||
goto err_mask;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
err_mask:
|
||||
_cairo_pattern_fini (&command->mask.base);
|
||||
err_source:
|
||||
_cairo_pattern_fini (&command->source.base);
|
||||
err_command:
|
||||
free(command);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy__stroke (cairo_recording_surface_t *surface,
|
||||
const cairo_command_t *src)
|
||||
{
|
||||
cairo_command_stroke_t *command;
|
||||
cairo_status_t status;
|
||||
|
||||
command = malloc (sizeof (*command));
|
||||
if (unlikely (command == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
_command_init_copy (surface, &command->header, &src->header);
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->source.base,
|
||||
&src->stroke.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_command;
|
||||
|
||||
status = _cairo_path_fixed_init_copy (&command->path, &src->stroke.path);
|
||||
if (unlikely (status))
|
||||
goto err_source;
|
||||
|
||||
status = _cairo_stroke_style_init_copy (&command->style,
|
||||
&src->stroke.style);
|
||||
if (unlikely (status))
|
||||
goto err_path;
|
||||
|
||||
command->ctm = src->stroke.ctm;
|
||||
command->ctm_inverse = src->stroke.ctm_inverse;
|
||||
command->tolerance = src->stroke.tolerance;
|
||||
command->antialias = src->stroke.antialias;
|
||||
|
||||
status = _cairo_recording_surface_commit (surface, &command->header);
|
||||
if (unlikely (status))
|
||||
goto err_style;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
err_style:
|
||||
_cairo_stroke_style_fini (&command->style);
|
||||
err_path:
|
||||
_cairo_path_fixed_fini (&command->path);
|
||||
err_source:
|
||||
_cairo_pattern_fini (&command->source.base);
|
||||
err_command:
|
||||
free(command);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy__fill (cairo_recording_surface_t *surface,
|
||||
const cairo_command_t *src)
|
||||
{
|
||||
cairo_command_fill_t *command;
|
||||
cairo_status_t status;
|
||||
|
||||
command = malloc (sizeof (*command));
|
||||
if (unlikely (command == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
_command_init_copy (surface, &command->header, &src->header);
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->source.base,
|
||||
&src->fill.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_command;
|
||||
|
||||
status = _cairo_path_fixed_init_copy (&command->path, &src->fill.path);
|
||||
if (unlikely (status))
|
||||
goto err_source;
|
||||
|
||||
command->fill_rule = src->fill.fill_rule;
|
||||
command->tolerance = src->fill.tolerance;
|
||||
command->antialias = src->fill.antialias;
|
||||
|
||||
status = _cairo_recording_surface_commit (surface, &command->header);
|
||||
if (unlikely (status))
|
||||
goto err_path;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
err_path:
|
||||
_cairo_path_fixed_fini (&command->path);
|
||||
err_source:
|
||||
_cairo_pattern_fini (&command->source.base);
|
||||
err_command:
|
||||
free(command);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy__glyphs (cairo_recording_surface_t *surface,
|
||||
const cairo_command_t *src)
|
||||
{
|
||||
cairo_command_show_text_glyphs_t *command;
|
||||
cairo_status_t status;
|
||||
|
||||
command = malloc (sizeof (*command));
|
||||
if (unlikely (command == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
_command_init_copy (surface, &command->header, &src->header);
|
||||
|
||||
status = _cairo_pattern_init_copy (&command->source.base,
|
||||
&src->show_text_glyphs.source.base);
|
||||
if (unlikely (status))
|
||||
goto err_command;
|
||||
|
||||
command->utf8 = NULL;
|
||||
command->utf8_len = src->show_text_glyphs.utf8_len;
|
||||
command->glyphs = NULL;
|
||||
command->num_glyphs = src->show_text_glyphs.num_glyphs;
|
||||
command->clusters = NULL;
|
||||
command->num_clusters = src->show_text_glyphs.num_clusters;
|
||||
|
||||
if (command->utf8_len) {
|
||||
command->utf8 = malloc (command->utf8_len);
|
||||
if (unlikely (command->utf8 == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err_arrays;
|
||||
}
|
||||
memcpy (command->utf8, src->show_text_glyphs.utf8, command->utf8_len);
|
||||
}
|
||||
if (command->num_glyphs) {
|
||||
command->glyphs = _cairo_malloc_ab (command->num_glyphs,
|
||||
sizeof (command->glyphs[0]));
|
||||
if (unlikely (command->glyphs == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err_arrays;
|
||||
}
|
||||
memcpy (command->glyphs, src->show_text_glyphs.glyphs,
|
||||
sizeof (command->glyphs[0]) * command->num_glyphs);
|
||||
}
|
||||
if (command->num_clusters) {
|
||||
command->clusters = _cairo_malloc_ab (command->num_clusters,
|
||||
sizeof (command->clusters[0]));
|
||||
if (unlikely (command->clusters == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto err_arrays;
|
||||
}
|
||||
memcpy (command->clusters, src->show_text_glyphs.clusters,
|
||||
sizeof (command->clusters[0]) * command->num_clusters);
|
||||
}
|
||||
|
||||
command->cluster_flags = src->show_text_glyphs.cluster_flags;
|
||||
|
||||
command->scaled_font =
|
||||
cairo_scaled_font_reference (src->show_text_glyphs.scaled_font);
|
||||
|
||||
status = _cairo_recording_surface_commit (surface, &command->header);
|
||||
if (unlikely (status))
|
||||
goto err_arrays;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
err_arrays:
|
||||
free (command->utf8);
|
||||
free (command->glyphs);
|
||||
free (command->clusters);
|
||||
_cairo_pattern_fini (&command->source.base);
|
||||
err_command:
|
||||
free(command);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_recording_surface_copy (cairo_recording_surface_t *dst,
|
||||
cairo_recording_surface_t *src)
|
||||
{
|
||||
cairo_command_t **elements;
|
||||
int i, num_elements;
|
||||
cairo_status_t status;
|
||||
|
||||
elements = _cairo_array_index (&src->commands, 0);
|
||||
num_elements = src->commands.num_elements;
|
||||
for (i = 0; i < num_elements; i++) {
|
||||
const cairo_command_t *command = elements[i];
|
||||
|
||||
switch (command->header.type) {
|
||||
case CAIRO_COMMAND_PAINT:
|
||||
status = _cairo_recording_surface_copy__paint (dst, command);
|
||||
break;
|
||||
|
||||
case CAIRO_COMMAND_MASK:
|
||||
status = _cairo_recording_surface_copy__mask (dst, command);
|
||||
break;
|
||||
|
||||
case CAIRO_COMMAND_STROKE:
|
||||
status = _cairo_recording_surface_copy__stroke (dst, command);
|
||||
break;
|
||||
|
||||
case CAIRO_COMMAND_FILL:
|
||||
status = _cairo_recording_surface_copy__fill (dst, command);
|
||||
break;
|
||||
|
||||
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
|
||||
status = _cairo_recording_surface_copy__glyphs (dst, command);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
}
|
||||
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_recording_surface_snapshot:
|
||||
* @surface: a #cairo_surface_t which must be a recording surface
|
||||
|
|
@ -1131,7 +1441,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
|
|||
surface->optimize_clears = TRUE;
|
||||
|
||||
_cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
|
||||
status = _cairo_recording_surface_replay (&other->base, &surface->base);
|
||||
status = _cairo_recording_surface_copy (other, surface);
|
||||
if (unlikely (status)) {
|
||||
cairo_surface_destroy (&surface->base);
|
||||
return _cairo_surface_create_in_error (status);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue