[cairo-commit] 4 commits - src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-dispatch-private.h src/cairo-gl-msaa-compositor.c src/cairo-gl-private.h src/cairo-gl-surface.c src/Makefile.sources

Chris Wilson ickle at kemper.freedesktop.org
Thu Oct 13 06:45:47 PDT 2011


 src/Makefile.sources            |    1 
 src/cairo-gl-composite.c        |  180 +++++++++++++++-
 src/cairo-gl-device.c           |   34 ++-
 src/cairo-gl-dispatch-private.h |    5 
 src/cairo-gl-msaa-compositor.c  |  428 ++++++++++++++++++++++++++++++++++++++++
 src/cairo-gl-private.h          |   30 ++
 src/cairo-gl-surface.c          |    4 
 7 files changed, 667 insertions(+), 15 deletions(-)

New commits:
commit c25027f2a1570b78c314896a127e518db370645c
Author: Martin Robinson <mrobinson at webkit.org>
Date:   Fri Oct 7 15:34:13 2011 -0700

    gl/msaa: Support for solid color strokes.
    
    Add support for basic solid color strokes using the fixed path
    stroke shaper. Currently components of the stroke overlap, but
    that will be handled in the following patch.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index f260c1d..2f9697a 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -789,7 +789,7 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 
 static void
 _cairo_gl_composite_emit_tristrip_vertex (cairo_gl_context_t	*ctx,
-					  cairo_point_t		*point)
+					  const cairo_point_t	*point)
 {
     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
 
@@ -841,7 +841,7 @@ _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t	*ctx,
 cairo_int_status_t
 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
 					   cairo_gl_composite_t	*setup,
-					   cairo_point_t	quad[4])
+					   const cairo_point_t	quad[4])
 {
     _cairo_gl_composite_prepare_buffer (ctx, 4);
 
@@ -857,6 +857,19 @@ _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
     return _cairo_gl_composite_append_vertex_indices (ctx, 4);
 }
 
+cairo_int_status_t
+_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t	*ctx,
+					       cairo_gl_composite_t	*setup,
+					       const cairo_point_t	 triangle[3])
+{
+    _cairo_gl_composite_prepare_buffer (ctx, 3);
+
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &triangle[0]);
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &triangle[1]);
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &triangle[2]);
+    return _cairo_gl_composite_append_vertex_indices (ctx, 3);
+}
+
 cairo_status_t
 _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t	*setup,
 				    cairo_gl_context_t		**ctx_out)
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 3475499..7a0e828 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -47,6 +47,11 @@
 #include "cairo-gl-private.h"
 #include "cairo-traps-private.h"
 
+struct _tristrip_composite_info {
+    cairo_gl_composite_t	setup;
+    cairo_gl_context_t		*ctx;
+};
+
 static cairo_int_status_t
 _draw_trap (cairo_gl_context_t		*ctx,
 	    cairo_gl_composite_t	*setup,
@@ -94,6 +99,33 @@ _draw_traps (cairo_gl_context_t		*ctx,
 }
 
 static cairo_int_status_t
+_draw_triangle_fan (cairo_gl_context_t		*ctx,
+		    cairo_gl_composite_t	*setup,
+		    const cairo_point_t		*midpt,
+		    const cairo_point_t		*points,
+		    int				 npoints)
+{
+    int i;
+
+    /* Our strategy here is to not even try to build a triangle fan, but to
+       draw each triangle as if it was an unconnected member of a triangle strip. */
+    for (i = 1; i < npoints; i++) {
+	cairo_int_status_t status;
+	cairo_point_t triangle[3];
+
+	triangle[0] = *midpt;
+	triangle[1] = points[i - 1];
+	triangle[2] = points[i];
+
+	status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
+	if (unlikely (status))
+	    return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 _draw_clip (cairo_gl_context_t		*ctx,
 	    cairo_gl_composite_t	*setup,
 	    cairo_clip_t		*clip)
@@ -185,6 +217,36 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+static cairo_status_t
+_stroke_shaper_add_triangle (void			*closure,
+			     const cairo_point_t	 triangle[3])
+{
+    struct _tristrip_composite_info *info = closure;
+    return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
+							  &info->setup,
+							  triangle);
+}
+
+static cairo_status_t
+_stroke_shaper_add_triangle_fan (void			*closure,
+				 const cairo_point_t	*midpoint,
+				 const cairo_point_t	*points,
+				 int			 npoints)
+{
+    struct _tristrip_composite_info *info = closure;
+    return _draw_triangle_fan (info->ctx, &info->setup,
+			       midpoint, points, npoints);
+}
+
+static cairo_status_t
+_stroke_shaper_add_quad (void			*closure,
+			 const cairo_point_t	 quad[4])
+{
+    struct _tristrip_composite_info *info = closure;
+    return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
+						      quad);
+}
+
 static cairo_int_status_t
 _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
 				  cairo_composite_rectangles_t	*composite,
@@ -195,7 +257,74 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
 				  double			 tolerance,
 				  cairo_antialias_t		 antialias)
 {
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    cairo_int_status_t status;
+    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+    struct _tristrip_composite_info info;
+
+    if (antialias != CAIRO_ANTIALIAS_NONE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_gl_composite_init (&info.setup,
+				       composite->op,
+				       dst,
+				       FALSE, /* assume_component_alpha */
+				       &composite->bounded);
+    if (unlikely (status))
+	return status;
+
+    info.ctx = NULL;
+
+    status = _cairo_gl_composite_set_source (&info.setup,
+					     &composite->source_pattern.base,
+					     composite->bounded.x,
+					     composite->bounded.y,
+					     composite->bounded.x,
+					     composite->bounded.y,
+					     composite->bounded.width,
+					     composite->bounded.height);
+    if (unlikely (status))
+	goto finish;
+
+    status = _cairo_gl_composite_begin_tristrip (&info.setup, &info.ctx);
+    if (unlikely (status))
+	goto finish;
+
+    glScissor (composite->unbounded.x, composite->unbounded.y,
+	       composite->unbounded.width, composite->unbounded.height);
+    glEnable (GL_SCISSOR_TEST);
+
+    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
+						       composite->clip))
+    {
+	status = _draw_clip_to_stencil_buffer (info.ctx, &info.setup, composite->clip);
+	if (unlikely (status))
+	    goto finish;
+    }
+
+    status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
+						 style,
+						 ctm,
+						 ctm_inverse,
+						 tolerance,
+						 _stroke_shaper_add_triangle,
+						 _stroke_shaper_add_triangle_fan,
+						 _stroke_shaper_add_quad,
+						 &info);
+    if (unlikely (status))
+	goto finish;
+
+    _cairo_gl_composite_flush (info.ctx);
+
+finish:
+    _cairo_gl_composite_fini (&info.setup);
+
+    if (info.ctx) {
+	glDisable (GL_SCISSOR_TEST);
+	_disable_stencil_buffer ();
+	status = _cairo_gl_context_release (info.ctx, status);
+    }
+
+    return status;
 }
 
 static cairo_int_status_t
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index f8bf571..ec7f8b2 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -507,7 +507,12 @@ _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t	*setup,
 cairo_int_status_t
 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
 					   cairo_gl_composite_t	*setup,
-					   cairo_point_t	 quad[4]);
+					   const cairo_point_t	 quad[4]);
+
+cairo_int_status_t
+_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t	*ctx,
+					       cairo_gl_composite_t	*setup,
+					       const cairo_point_t	 triangle[3]);
 
 cairo_private void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
commit 32aa361c5ea0c761e26bc6fd94acfddd8df3b759
Author: Martin Robinson <mrobinson at webkit.org>
Date:   Tue Sep 27 08:42:36 2011 -0700

    gl/msaa: Add clipping support
    
    Adds basic clipping to the OpenGL MSAA compositor via the
    depth and stencil buffers. Stenciling and depth bits are
    stored in a renderbuffer.
    
    Note that we only attach renderbuffers to surfaces created by ourselves
    and not for foreign drawables (e.g. X Windows).

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 33af08e..01fa52a 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -207,6 +207,12 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     ctx->has_mesa_pack_invert =
 	_cairo_gl_has_extension ("GL_MESA_pack_invert");
 
+    ctx->has_packed_depth_stencil =
+	((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
+	 _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
+	(gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	 _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
+
     ctx->current_operator = -1;
     ctx->gl_flavor = gl_flavor;
 
@@ -256,7 +262,7 @@ _cairo_gl_context_activate (cairo_gl_context_t *ctx,
     if (ctx->max_textures <= (GLint) tex_unit) {
         if (tex_unit < 2) {
             _cairo_gl_composite_flush (ctx);
-            _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);   
+            _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
         }
         glActiveTexture (ctx->max_textures - 1);
     } else {
@@ -289,6 +295,24 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
     glReadBuffer (GL_COLOR_ATTACHMENT0);
 #endif
 
+    if (ctx->has_packed_depth_stencil) {
+#if CAIRO_HAS_GL_SURFACE
+	GLenum internal_format = GL_DEPTH_STENCIL;
+#elif CAIRO_HAS_GLESV2_SURFACE
+	GLenum internal_format = GL_DEPTH24_STENCIL8_OES,
+#endif
+
+	dispatch->GenRenderbuffers (1, &surface->depth_stencil);
+	dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
+	dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format,
+				       surface->width, surface->height);
+
+	ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+					       GL_RENDERBUFFER, surface->depth_stencil);
+	ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+					       GL_RENDERBUFFER, surface->depth_stencil);
+    }
+
     status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
     if (status != GL_FRAMEBUFFER_COMPLETE) {
 	const char *str;
@@ -367,6 +391,7 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
     } else {
         ctx->make_current (ctx, surface);
         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
+
 #if CAIRO_HAS_GL_SURFACE
         glDrawBuffer (GL_BACK_LEFT);
         glReadBuffer (GL_BACK_LEFT);
diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
index 751913c..fdd0cf6 100644
--- a/src/cairo-gl-dispatch-private.h
+++ b/src/cairo-gl-dispatch-private.h
@@ -109,6 +109,11 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
     DISPATCH_ENTRY_EXT (FramebufferTexture2D),
     DISPATCH_ENTRY_EXT (CheckFramebufferStatus),
     DISPATCH_ENTRY_EXT (DeleteFramebuffers),
+    DISPATCH_ENTRY_EXT (GenRenderbuffers),
+    DISPATCH_ENTRY_EXT (BindRenderbuffer),
+    DISPATCH_ENTRY_EXT (RenderbufferStorage),
+    DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
+    DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
     DISPATCH_ENTRY_LAST
 };
 
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index ab5501d..3475499 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -81,8 +81,8 @@ _draw_traps (cairo_gl_context_t		*ctx,
 	     cairo_gl_composite_t	*setup,
 	     cairo_traps_t		*traps)
 {
-    int i;
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+    int i;
 
     for (i = 0; i < traps->num_traps; i++) {
 	cairo_trapezoid_t *trap = traps->traps + i;
@@ -94,6 +94,84 @@ _draw_traps (cairo_gl_context_t		*ctx,
 }
 
 static cairo_int_status_t
+_draw_clip (cairo_gl_context_t		*ctx,
+	    cairo_gl_composite_t	*setup,
+	    cairo_clip_t		*clip)
+{
+    cairo_int_status_t status;
+    cairo_traps_t traps;
+
+    cairo_polygon_t polygon;
+    cairo_antialias_t antialias;
+    cairo_fill_rule_t fill_rule;
+
+    status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
+    if (unlikely (status))
+	return status;
+
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	_cairo_polygon_fini (&polygon);
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    _cairo_traps_init (&traps);
+    status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
+							&polygon,
+							fill_rule);
+    _cairo_polygon_fini (&polygon);
+    if (unlikely (status))
+	return status;
+
+    status = _draw_traps (ctx, setup, &traps);
+
+    _cairo_traps_fini (&traps);
+    return status;
+}
+
+static void
+_disable_stencil_buffer (void)
+{
+    glDisable (GL_STENCIL_TEST);
+    glDepthMask (GL_FALSE);
+}
+
+static cairo_int_status_t
+_draw_clip_to_stencil_buffer (cairo_gl_context_t	*ctx,
+			      cairo_gl_composite_t	*setup,
+			      cairo_clip_t		*clip)
+{
+    cairo_int_status_t status;
+
+    assert (! _cairo_clip_is_all_clipped (clip));
+
+    if (! setup->dst->depth_stencil)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    glDepthMask (GL_TRUE);
+    glEnable (GL_STENCIL_TEST);
+    glClearStencil (0);
+    glClear (GL_STENCIL_BUFFER_BIT);
+    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
+    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
+    glColorMask (0, 0, 0, 0);
+
+    status = _draw_clip (ctx, setup, clip);
+    if (unlikely (status)) {
+	_disable_stencil_buffer ();
+	return status;
+    }
+
+    /* We want to only render to the stencil buffer, so draw everything now. */
+    _cairo_gl_composite_flush (ctx);
+
+    glColorMask (1, 1, 1, 1);
+    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
+
+    return status;;
+}
+
+static cairo_int_status_t
 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t	*compositor,
 				 cairo_composite_rectangles_t	*composite)
 {
@@ -137,10 +215,6 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     if (antialias != CAIRO_ANTIALIAS_NONE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
-						       composite->clip))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
     _cairo_traps_init (&traps);
     status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
     if (unlikely (status))
@@ -169,6 +243,18 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto cleanup_setup;
 
+    glScissor (composite->unbounded.x, composite->unbounded.y,
+	       composite->unbounded.width, composite->unbounded.height);
+    glEnable (GL_SCISSOR_TEST);
+
+    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
+						       composite->clip))
+    {
+	status = _draw_clip_to_stencil_buffer (ctx, &setup, composite->clip);
+	if (unlikely (status))
+	    goto cleanup_setup;
+    }
+
     status = _draw_traps (ctx, &setup, &traps);
     if (unlikely (status))
         goto cleanup_setup;
@@ -176,8 +262,12 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     _cairo_gl_composite_flush (ctx);
 cleanup_setup:
     _cairo_gl_composite_fini (&setup);
-    if (ctx)
+
+    if (ctx) {
+	glDisable (GL_SCISSOR_TEST);
+	_disable_stencil_buffer ();
 	status = _cairo_gl_context_release (ctx, status);
+    }
 cleanup_traps:
     _cairo_traps_fini (&traps);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index d120870..f8bf571 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -116,7 +116,7 @@ typedef struct _cairo_gl_surface {
 
     GLuint tex; /* GL texture object containing our data. */
     GLuint fb; /* GL framebuffer object wrapping our data. */
-    GLuint depth; /* GL framebuffer object holding depth */
+    GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
     int owns_tex;
     cairo_bool_t needs_update;
 } cairo_gl_surface_t;
@@ -254,6 +254,14 @@ typedef struct _cairo_gl_dispatch {
 				    GLint level);
     GLenum (*CheckFramebufferStatus) (GLenum target);
     void (*DeleteFramebuffers) (GLsizei n, const GLuint* framebuffers);
+    void (*GenRenderbuffers) (GLsizei n, GLuint *renderbuffers);
+    void (*BindRenderbuffer) (GLenum target, GLuint renderbuffer);
+    void (*RenderbufferStorage) (GLenum target, GLenum internal_format,
+				 GLsizei width, GLsizei height);
+    void (*FramebufferRenderbuffer) (GLenum target, GLenum attachment,
+				     GLenum renderbuffer_ttarget, GLuint renderbuffer);
+    void (*DeleteRenderbuffers) (GLsizei n, GLuint *renderbuffers);
+
 } cairo_gl_dispatch_t;
 
 struct _cairo_gl_context {
@@ -299,6 +307,7 @@ struct _cairo_gl_context {
     GLfloat modelviewprojection_matrix[16];
     cairo_gl_flavor_t gl_flavor;
     cairo_bool_t has_map_buffer;
+    cairo_bool_t has_packed_depth_stencil;
 
     void (*acquire) (void *ctx);
     void (*release) (void *ctx);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9fcbc3e..c781ec4 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -919,10 +919,10 @@ _cairo_gl_surface_finish (void *abstract_surface)
     if (ctx->current_target == surface)
 	ctx->current_target = NULL;
 
-    if (surface->depth)
-        ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
     if (surface->fb)
         ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
+    if (surface->depth_stencil)
+        ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
     if (surface->owns_tex)
 	glDeleteTextures (1, &surface->tex);
 
commit 13d9d07ccd92454f8eb0a1f2d59c8829ac471cb4
Author: Martin Robinson <mrobinson at webkit.org>
Date:   Mon Sep 26 14:45:23 2011 -0700

    gl/msaa: Implement basic solid color fill
    
    Introduce the very basic functionality of an MSAA compositor
    for OpenGL. For this first patch only solid fills are supported.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 5bce04d..f260c1d 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -4,6 +4,7 @@
  * Copyright © 2009 Chris Wilson
  * Copyright © 2005,2010 Red Hat, Inc
  * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Samsung Electronics
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -38,6 +39,8 @@
  *	Chris Wilson <chris at chris-wilson.co.uk>
  *	Eric Anholt <eric at anholt.net>
  *	Alexandros Frantzis <alexandros.frantzis at linaro.org>
+ *	Henry Song <hsong at sisa.samsung.com>
+ *	Martin Robinson <mrobinson at igalia.com>
  */
 
 #include "cairoint.h"
@@ -571,6 +574,15 @@ FAIL:
 }
 
 static inline void
+_cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
+{
+    cairo_array_t* indices = &ctx->tristrip_indices;
+    const int *indices_array = _cairo_array_index_const (indices, 0);
+    glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_INT, indices_array);
+    _cairo_array_truncate (indices, 0);
+}
+
+static inline void
 _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
 			  unsigned int count)
 {
@@ -589,16 +601,9 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
     }
 }
 
-void
-_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
+static void
+_cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
 {
-    unsigned int count;
-
-    if (_cairo_gl_context_is_flushed (ctx))
-        return;
-
-    count = ctx->vb_offset / ctx->vertex_size;
-
     if (ctx->has_map_buffer)
 	ctx->dispatch.UnmapBuffer (GL_ARRAY_BUFFER);
     else
@@ -607,8 +612,22 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
 
     ctx->vb = NULL;
     ctx->vb_offset = 0;
+}
+
+void
+_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
+{
+    unsigned int count;
+
+    if (_cairo_gl_context_is_flushed (ctx))
+        return;
+
+    count = ctx->vb_offset / ctx->vertex_size;
+    _cairo_gl_composite_unmap_vertex_buffer (ctx);
 
-    if (ctx->clip_region) {
+    if ( _cairo_array_num_elements (&ctx->tristrip_indices) > 0) {
+	_cairo_gl_composite_draw_tristrip (ctx);
+    } else if (ctx->clip_region) {
 	int i, num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
 
 	for (i = 0; i < num_rectangles; i++) {
@@ -767,3 +786,131 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 
     return CAIRO_STATUS_SUCCESS;
 }
+
+static void
+_cairo_gl_composite_emit_tristrip_vertex (cairo_gl_context_t	*ctx,
+					  cairo_point_t		*point)
+{
+    GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+    *vb++ = _cairo_fixed_to_double (point->x);
+    *vb++ = _cairo_fixed_to_double (point->y);
+
+    ctx->vb_offset += ctx->vertex_size;
+}
+
+static cairo_int_status_t
+_cairo_gl_composite_append_vertex_indices (cairo_gl_context_t	*ctx,
+					   int			 number_of_new_indices)
+{
+    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+    cairo_array_t *indices = &ctx->tristrip_indices;
+    int number_of_indices = _cairo_array_num_elements (indices);
+    int current_vertex_index = 0;
+    int i;
+
+    assert (number_of_new_indices > 0);
+
+    /* If any preexisting triangle triangle strip indices exist on this
+       context, we insert a set of degenerate triangles from the last
+       preexisting vertex to our first one. */
+    if (number_of_indices > 0) {
+	const int *indices_array = _cairo_array_index_const (indices, 0);
+	current_vertex_index = indices_array[number_of_indices - 1];
+
+	status = _cairo_array_append (indices, &current_vertex_index);
+	if (unlikely (status))
+	    return status;
+
+	current_vertex_index++;
+	status =_cairo_array_append (indices, &current_vertex_index);
+	if (unlikely (status))
+	    return status;
+    }
+
+    for (i = 0; i < number_of_new_indices; i++) {
+	status = _cairo_array_append (indices, &current_vertex_index);
+	current_vertex_index++;
+	if (unlikely (status))
+	    return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
+					   cairo_gl_composite_t	*setup,
+					   cairo_point_t	quad[4])
+{
+    _cairo_gl_composite_prepare_buffer (ctx, 4);
+
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[0]);
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[1]);
+
+    /* Cairo stores quad vertices in counter-clockwise order, but we need to
+       emit them from top to bottom in the triangle strip, so we need to reverse
+       the order of the last two vertices. */
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[3]);
+    _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[2]);
+
+    return _cairo_gl_composite_append_vertex_indices (ctx, 4);
+}
+
+cairo_status_t
+_cairo_gl_composite_begin_tristrip (cairo_gl_composite_t	*setup,
+				    cairo_gl_context_t		**ctx_out)
+{
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+    cairo_gl_shader_t *shader;
+    int src_size, dst_size;
+
+    cairo_gl_operand_t default_mask;
+    memset (&default_mask, 0, sizeof (cairo_gl_operand_t));
+
+    assert (setup->dst);
+
+    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+    *ctx_out = ctx;
+
+    /* Finish any pending operations from other GL compositors. */
+    if (! _cairo_gl_context_is_flushed (ctx))
+	_cairo_gl_composite_flush (ctx);
+
+    glEnable (GL_BLEND);
+
+    status = _cairo_gl_get_shader_by_type (ctx,
+					   &setup->src,
+					   &default_mask,
+					   setup->spans,
+					   CAIRO_GL_SHADER_IN_NORMAL,
+                                           &shader);
+    if (unlikely (status)) {
+	status = _cairo_gl_context_release (ctx, status);
+	return status;
+    }
+
+    _cairo_gl_context_set_destination (ctx, setup->dst);
+
+    _cairo_gl_set_operator (ctx, setup->op, FALSE);
+    _cairo_gl_set_shader (ctx, shader);
+    _cairo_gl_composite_bind_to_shader (ctx, setup);
+
+    dst_size  = 2 * sizeof (GLfloat);
+    src_size  = _cairo_gl_operand_get_vertex_size (setup->src.type);
+
+    ctx->vertex_size = dst_size + src_size;
+
+    ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
+    ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
+				       GL_FLOAT, GL_FALSE, ctx->vertex_size, NULL);
+    ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
+
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src,
+				     ctx->vertex_size, dst_size);
+
+    return status;
+}
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index f20850e..33af08e 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -132,6 +132,8 @@ _gl_destroy (void *device)
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
 	_cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
 
+    _cairo_array_fini (&ctx->tristrip_indices);
+
     cairo_region_destroy (ctx->clip_region);
 
     free (ctx->vb_mem);
@@ -163,7 +165,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
-    ctx->compositor = _cairo_gl_span_compositor_get ();
+    //ctx->compositor = _cairo_gl_span_compositor_get ();
+    ctx->compositor = _cairo_gl_msaa_compositor_get ();
 
     memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
     cairo_list_init (&ctx->fonts);
@@ -227,6 +230,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	}
     }
 
+    _cairo_array_init (&ctx->tristrip_indices, sizeof(int));
+
     /* PBO for any sort of texture upload */
     dispatch->GenBuffers (1, &ctx->texture_load_pbo);
     dispatch->GenBuffers (1, &ctx->vbo);
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 8e2c2ed..ab5501d 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -48,6 +48,52 @@
 #include "cairo-traps-private.h"
 
 static cairo_int_status_t
+_draw_trap (cairo_gl_context_t		*ctx,
+	    cairo_gl_composite_t	*setup,
+	    cairo_trapezoid_t		*trap)
+{
+    cairo_point_t quad[4];
+
+    quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
+							  &trap->left.p2,
+							  trap->top);
+    quad[0].y = trap->top;
+
+    quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
+						      &trap->left.p2,
+						      trap->bottom);
+    quad[1].y = trap->bottom;
+
+    quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
+						      &trap->right.p2,
+						      trap->bottom);
+    quad[2].y = trap->bottom;
+
+    quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
+						      &trap->right.p2,
+						      trap->top);
+    quad[3].y = trap->top;
+    return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
+}
+
+static cairo_int_status_t
+_draw_traps (cairo_gl_context_t		*ctx,
+	     cairo_gl_composite_t	*setup,
+	     cairo_traps_t		*traps)
+{
+    int i;
+    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+    for (i = 0; i < traps->num_traps; i++) {
+	cairo_trapezoid_t *trap = traps->traps + i;
+	if (unlikely ((status = _draw_trap (ctx, setup, trap))))
+	    return status;
+    }
+
+   return status;
+}
+
+static cairo_int_status_t
 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t	*compositor,
 				 cairo_composite_rectangles_t	*composite)
 {
@@ -82,7 +128,60 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
 				double				 tolerance,
 				cairo_antialias_t		 antialias)
 {
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    cairo_gl_composite_t setup;
+    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+    cairo_gl_context_t *ctx = NULL;
+    cairo_int_status_t status;
+    cairo_traps_t traps;
+
+    if (antialias != CAIRO_ANTIALIAS_NONE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
+						       composite->clip))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    _cairo_traps_init (&traps);
+    status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
+    if (unlikely (status))
+	goto cleanup_traps;
+
+    status = _cairo_gl_composite_init (&setup,
+				       composite->op,
+				       dst,
+				       FALSE, /* assume_component_alpha */
+				       &composite->bounded);
+    if (unlikely (status))
+	goto cleanup_traps;
+
+    status = _cairo_gl_composite_set_source (&setup,
+					     &composite->source_pattern.base,
+					     composite->bounded.x,
+					     composite->bounded.y,
+					     composite->bounded.x,
+					     composite->bounded.y,
+					     composite->bounded.width,
+					     composite->bounded.height);
+    if (unlikely (status))
+	goto cleanup_setup;
+
+    status = _cairo_gl_composite_begin_tristrip (&setup, &ctx);
+    if (unlikely (status))
+	goto cleanup_setup;
+
+    status = _draw_traps (ctx, &setup, &traps);
+    if (unlikely (status))
+        goto cleanup_setup;
+
+    _cairo_gl_composite_flush (ctx);
+cleanup_setup:
+    _cairo_gl_composite_fini (&setup);
+    if (ctx)
+	status = _cairo_gl_context_release (ctx, status);
+cleanup_traps:
+    _cairo_traps_fini (&traps);
+
+    return status;
 }
 
 static void
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 5249274..d120870 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -56,6 +56,7 @@
 #include "cairo-rtree-private.h"
 #include "cairo-scaled-font-private.h"
 #include "cairo-spans-compositor-private.h"
+#include "cairo-array-private.h"
 
 #include <assert.h>
 
@@ -291,6 +292,7 @@ struct _cairo_gl_context {
     unsigned int vb_offset;
     unsigned int vertex_size;
     cairo_region_t *clip_region;
+    cairo_array_t tristrip_indices;
 
     cairo_bool_t has_mesa_pack_invert;
     cairo_gl_dispatch_t dispatch;
@@ -489,6 +491,15 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
 cairo_private void
 _cairo_gl_composite_flush (cairo_gl_context_t *ctx);
 
+cairo_private cairo_status_t
+_cairo_gl_composite_begin_tristrip (cairo_gl_composite_t	*setup,
+				    cairo_gl_context_t		**ctx_out);
+
+cairo_int_status_t
+_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
+					   cairo_gl_composite_t	*setup,
+					   cairo_point_t	 quad[4]);
+
 cairo_private void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit);
commit 9f85eb52d834200802a05ac1dd5fa045217adf5f
Author: Martin Robinson <mrobinson at webkit.org>
Date:   Tue Oct 11 09:37:51 2011 -0700

    gl/msaa: Introduce an MSAA compositor for OpenGL
    
    The MSAA compositor will composite OpenGL primitives directly and
    anti-alias via the GPU.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 2320f29..84df00a 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -366,6 +366,7 @@ cairo_gl_sources = cairo-gl-composite.c \
 		   cairo-gl-info.c \
 		   cairo-gl-operand.c \
 		   cairo-gl-shaders.c \
+		   cairo-gl-msaa-compositor.c \
 		   cairo-gl-spans-compositor.c \
 		   cairo-gl-traps-compositor.c \
 		   cairo-gl-surface.c
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
new file mode 100644
index 0000000..8e2c2ed
--- /dev/null
+++ b/src/cairo-gl-msaa-compositor.c
@@ -0,0 +1,110 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2011 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Henry Song <hsong at sisa.samsung.com>
+ *	Martin Robinson <mrobinson at igalia.com>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-gl-private.h"
+#include "cairo-traps-private.h"
+
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_paint (const cairo_compositor_t	*compositor,
+				 cairo_composite_rectangles_t	*composite)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
+				cairo_composite_rectangles_t	*composite)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
+				  cairo_composite_rectangles_t	*composite,
+				  const cairo_path_fixed_t	*path,
+				  const cairo_stroke_style_t	*style,
+				  const cairo_matrix_t		*ctm,
+				  const cairo_matrix_t		*ctm_inverse,
+				  double			 tolerance,
+				  cairo_antialias_t		 antialias)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
+				cairo_composite_rectangles_t	*composite,
+				const cairo_path_fixed_t	*path,
+				cairo_fill_rule_t		 fill_rule,
+				double				 tolerance,
+				cairo_antialias_t		 antialias)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static void
+_cairo_gl_msaa_compositor_init (cairo_compositor_t	 *compositor,
+				const cairo_compositor_t *delegate)
+{
+    compositor->delegate = delegate;
+
+    compositor->paint = _cairo_gl_msaa_compositor_paint;
+    compositor->mask = _cairo_gl_msaa_compositor_mask;
+    compositor->fill = _cairo_gl_msaa_compositor_fill;
+    compositor->stroke = _cairo_gl_msaa_compositor_stroke;
+    /* always fallback to common glyph cache implmentation */
+}
+
+const cairo_compositor_t *
+_cairo_gl_msaa_compositor_get (void)
+{
+    static cairo_compositor_t compositor;
+    if (compositor.delegate == NULL)
+	_cairo_gl_msaa_compositor_init (&compositor,
+					_cairo_gl_span_compositor_get ());
+
+    return &compositor;
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 9027178..5249274 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -646,6 +646,9 @@ cairo_private void
 _cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
 
 cairo_private const cairo_compositor_t *
+_cairo_gl_msaa_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
 _cairo_gl_span_compositor_get (void);
 
 cairo_private const cairo_compositor_t *


More information about the cairo-commit mailing list