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

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E434AC781@sisaex01sj>
From 1b95f6946f028988e6905060aa5ee037ab52990f Mon Sep 17 00:00:00 2001
From: Henry Song <[email protected]>
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
-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.