[cairo-commit] src/cairo-recording-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Oct 3 09:09:22 PDT 2012


 src/cairo-recording-surface.c |  312 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 311 insertions(+), 1 deletion(-)

New commits:
commit 8020e0bc8cbd3e5ac188eb305b74ae1c1f362a31
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Oct 3 17:01:41 2012 +0100

    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 at chris-wilson.co.uk>

diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 02d8afd..73fc48a 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);


More information about the cairo-commit mailing list