summaryrefslogtreecommitdiff
path: root/src/cairo-recording-surface.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-10-03 17:01:41 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-10-03 17:08:06 +0100
commit8020e0bc8cbd3e5ac188eb305b74ae1c1f362a31 (patch)
treeb064b741579eb89b9573849ef0e3649ec635f9a3 /src/cairo-recording-surface.c
parent797441093a8346003552e0cf89aef2a644ff53ab (diff)
downloadcairo-8020e0bc8cbd3e5ac188eb305b74ae1c1f362a31.tar.gz
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>
Diffstat (limited to 'src/cairo-recording-surface.c')
-rw-r--r--src/cairo-recording-surface.c312
1 files changed, 311 insertions, 1 deletions
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 02d8afd56..73fc48ad0 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -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);