[cairo] [patch] gl/msaa: upload image inplace instead of creating extra scratch gl surface

Henry (Yu) Song - SISA hsong at sisa.samsung.com
Tue Jan 29 09:19:53 PST 2013


>From 1b95f6946f028988e6905060aa5ee037ab52990f Mon Sep 17 00:00:00 2001
From: Henry Song <henry.song at samsung.com>
Date: Tue, 29 Jan 2013 09:15:46 -0800
Subject: [PATCH] gl/msaa: upload image inplace in paint if the source pattern
 is an image and pattern is pixel-aligned without scale and
 rotation. This saves GPU memory without creating extra
 scratch surface

---
 src/cairo-gl-msaa-compositor.c |  117 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 116 insertions(+), 1 deletion(-)

diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 54772ef..b9ffd8f 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -47,6 +47,8 @@
 #include "cairo-gl-private.h"
 #include "cairo-path-private.h"
 #include "cairo-traps-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-offset-private.h"
 
 static cairo_bool_t
 can_use_msaa_compositor (cairo_gl_surface_t *surface,
@@ -213,6 +215,112 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
 }
 
 static cairo_bool_t
+_pattern_is_pixel_aligned (const cairo_pattern_t *pattern)
+{
+    return pattern->matrix.xx == 1 &&
+	   pattern->matrix.yy == 1 &&
+	   pattern->matrix.xy == 0 &&
+	   pattern->matrix.yx == 0 &&
+	   ceil (pattern->matrix.x0) == pattern->matrix.x0 &&
+	   ceil (pattern->matrix.y0) == pattern->matrix.y0;
+}
+
+static cairo_bool_t
+_pattern_is_image_surface (const cairo_pattern_t *pattern)
+{
+    cairo_surface_t *surface;
+
+    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return FALSE;
+
+    surface = ((cairo_surface_pattern_t *)pattern)->surface;
+    return surface->type == CAIRO_SURFACE_TYPE_IMAGE;
+}
+
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_upload_image_inplace (const cairo_compositor_t *compositor,
+						cairo_composite_rectangles_t *composite)
+{
+    cairo_image_surface_t *image, *rgba_image = NULL;
+    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+    cairo_gl_context_t *ctx;
+    cairo_gl_dispatch_t *dispatch;
+    pixman_format_code_t pixman_format;
+
+    const cairo_pattern_t *pattern = composite->original_source_pattern;
+    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+
+    if (_pattern_is_image_surface (pattern) &&
+	_pattern_is_pixel_aligned (pattern) &&
+	cairo_pattern_get_extend ((cairo_pattern_t *)pattern) == CAIRO_EXTEND_NONE &&
+	_cairo_gl_surface_is_texture (dst)) {
+	if ((dst->base.is_clear && 
+	     (composite->op == CAIRO_OPERATOR_OVER ||
+	      composite->op == CAIRO_OPERATOR_ADD)) ||
+	    composite->op == CAIRO_OPERATOR_SOURCE) {
+	    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+	    if (unlikely (status))
+		return status;
+
+	    dispatch = &ctx->dispatch;
+
+	    image = (cairo_image_surface_t *)
+		cairo_surface_map_to_image (&dst->base, &composite->bounded);
+
+	    /* GLES2 core profile only supports RGBA/RGB/ALPHA, we need
+	     * to convert to RGBA if mapped image is not right format
+	     */
+	    pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+	    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+		image->pixman_format != pixman_format) {
+		rgba_image = (cairo_image_surface_t *)
+		    _cairo_image_surface_create_with_pixman_format (NULL,
+								    pixman_format,
+								    composite->bounded.width,
+								    composite->bounded.height,
+								    0);
+		/* dst is either clear or we have right operator, so
+		 * we don't need to paint image to rgba_image
+		 */
+		rgba_image->base.device_transform = image->base.device_transform;
+		rgba_image->base.device_transform_inverse = image->base.device_transform_inverse;
+		cairo_surface_destroy (&image->base);
+		image = rgba_image;
+	    }
+
+	    status = _cairo_surface_offset_paint (&image->base,
+						  composite->bounded.x,
+						  composite->bounded.y,
+						  CAIRO_OPERATOR_SOURCE,
+						  pattern,
+						  NULL);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (&image->base);
+		status = _cairo_gl_context_release (ctx, status);
+		return status;
+	    }
+
+	    /* ensure we are bind to the current FB) and multisample
+	     * buffer has been resolved
+	     */
+	    _cairo_gl_context_set_destination (ctx, dst, FALSE);
+	    dispatch->BindFramebuffer (GL_FRAMEBUFFER, 0);
+
+	    /* reset surface->parent, otherwise, unmap_image
+	     * calls backend paint again, which causes recursion
+	     */
+	    image->parent = NULL;
+	    cairo_surface_unmap_image (&dst->base, &image->base);
+	    dispatch->BindFramebuffer (GL_FRAMEBUFFER, dst->fb);
+
+	    status = _cairo_gl_context_release (ctx, status);
+	}
+    }
+
+    return status;
+}
+
+static cairo_bool_t
 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
 {
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
@@ -501,7 +609,14 @@ static cairo_int_status_t
 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t	*compositor,
 				 cairo_composite_rectangles_t	*composite)
 {
-    return _cairo_gl_msaa_compositor_mask (compositor, composite);
+    cairo_int_status_t status = 
+	_cairo_gl_msaa_compositor_upload_image_inplace (compositor,
+							composite);
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	return _cairo_gl_msaa_compositor_mask (compositor, composite);
+
+    return status;
 }
 
 static cairo_status_t
-- 
1.7.9.5


More information about the cairo mailing list