From 443fbf4352d797bb02d5456fbb08e2f623cf208c Mon Sep 17 00:00:00 2001 From: Henry Song Date: Mon, 26 Sep 2011 14:45:23 -0700 Subject: [PATCH 1/2] Introduce an MSAA OpenGL compositor. Introduce the very basic functionality of an MSAA compositor for OpenGL. For this first patch only solid fills are supported. The MSAA compositor will strive for fast rendering and work gradually toward correctness. --- src/Makefile.sources | 1 + src/cairo-gl-composite.c | 181 ++++++++++++++++++++++++-- src/cairo-gl-msaa-traps-compositor.c | 234 ++++++++++++++++++++++++++++++++++ src/cairo-gl-private.h | 14 ++ src/cairo-tristrip.c | 1 + 6 files changed, 425 insertions(+), 13 deletions(-) create mode 100644 src/cairo-gl-msaa-traps-compositor.c diff --git a/src/Makefile.sources b/src/Makefile.sources index 2320f29..b40388e 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -367,6 +367,7 @@ cairo_gl_sources = cairo-gl-composite.c \ cairo-gl-operand.c \ cairo-gl-shaders.c \ cairo-gl-spans-compositor.c \ + cairo-gl-msaa-traps-compositor.c \ cairo-gl-traps-compositor.c \ cairo-gl-surface.c diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index c59501e..8347f20 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 * Eric Anholt * Alexandros Frantzis + * Henry Song + * Martin Robinson */ #include "cairoint.h" @@ -573,6 +576,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) { @@ -591,16 +603,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 @@ -609,16 +614,29 @@ _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++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (ctx->clip_region, i, &rect); - - glScissor (rect.x, rect.y, rect.width, rect.height); +glScissor (rect.x, rect.y, rect.width, rect.height); _cairo_gl_composite_draw (ctx, count); } } else { @@ -769,3 +787,142 @@ _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 color[4]) +{ + GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset]; + + *vb++ = _cairo_fixed_to_double (point->x); + *vb++ = _cairo_fixed_to_double (point->y); + + *vb++ = color[0]; + *vb++ = color[1]; + *vb++ = color[2]; + *vb++ = color[3]; + + 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 triangle 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, ¤t_vertex_index); + if (unlikely (status)) + return status; + + current_vertex_index++; + status =_cairo_array_append (indices, ¤t_vertex_index); + if (unlikely (status)) + return status; + } + + for (i = 0; i < number_of_new_indices; i++) { + status = _cairo_array_append (indices, ¤t_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]) +{ + GLfloat *color = setup->src.constant.color; + _cairo_gl_composite_prepare_buffer (ctx, 4); + + _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[0], color); + _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[1], color); + + /* 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], color); + _cairo_gl_composite_emit_tristrip_vertex (ctx, &quad[2], color); + + 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) +{ + unsigned int coordinates_size, color_size; + + cairo_gl_context_t *ctx; + cairo_status_t status; + cairo_gl_shader_t *shader; + + 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); + + /* Each element of the vertex buffer contains two sections. The first is the + x and y coordinates of the vertex and the second is the 4 components of + the vertex color. For the constant color case these will not differ + between vertices. */ + coordinates_size = 2 * sizeof (GLfloat); + color_size = 4 * sizeof (GLfloat); + ctx->vertex_size = coordinates_size + color_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); + ctx->dispatch.VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4, + GL_FLOAT, GL_TRUE, ctx->vertex_size, + (void *) (uintptr_t) coordinates_size); + ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX); + + 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); @@ -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-traps-compositor.c b/src/cairo-gl-msaa-traps-compositor.c new file mode 100644 index 0000000..ed3fed8 --- /dev/null +++ b/src/cairo-gl-msaa-traps-compositor.c @@ -0,0 +1,234 @@ +/* -*- 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 + * Martin Robinson + */ + +#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 +_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 *extents) +{ + return compositor->delegate->paint (compositor->delegate, extents); +} + +static cairo_int_status_t +_cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + return compositor->delegate->mask (compositor->delegate, extents); +} + +static cairo_int_status_t +_cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + 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 compositor->delegate->stroke (compositor->delegate, + extents, + path, + style, + ctm, + ctm_inverse, + tolerance, + antialias); +} + +static cairo_int_status_t +_cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_status_t status; + cairo_traps_t traps; + + cairo_gl_composite_t setup; + cairo_gl_surface_t *dst = (cairo_gl_surface_t *) extents->surface; + cairo_gl_context_t *ctx = NULL; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + return compositor->delegate->fill (compositor->delegate, + extents, + path, + fill_rule, + tolerance, + antialias); + } + + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); + if (unlikely (status)) + goto FINISH; + + status = _cairo_gl_composite_init (&setup, + extents->op, + dst, + FALSE, /* assume_component_alpha */ + &extents->bounded); + if (unlikely (status)) + return status; + + status = _cairo_gl_composite_set_source (&setup, + &extents->source_pattern.base, + extents->bounded.x, + extents->bounded.y, + extents->bounded.x, + extents->bounded.y, + extents->bounded.width, + extents->bounded.height); + if (unlikely (status)) + goto FINISH; + + status = _cairo_gl_composite_begin_tristrip (&setup, &ctx); + if (unlikely (status)) + goto FINISH; + + status = _draw_traps (ctx, &setup, &traps); + if (unlikely (status)) + goto FINISH; + + _cairo_gl_composite_flush (ctx); + +FINISH: + _cairo_traps_fini (&traps); + _cairo_gl_composite_fini (&setup); + if (ctx) + status = _cairo_gl_context_release (ctx, status); + + return status; +} + +static cairo_int_status_t +_cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + return compositor->delegate->glyphs (compositor->delegate, + extents, + scaled_font, + glyphs, + num_glyphs, + overlap); + return CAIRO_STATUS_SUCCESS; +} + +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; + compositor->glyphs = _cairo_gl_msaa_compositor_glyphs; +} + +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 e1005ba..1bb59b3 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 @@ -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); @@ -648,6 +659,9 @@ _cairo_gl_span_compositor_get (void); cairo_private const cairo_compositor_t * _cairo_gl_traps_compositor_get (void); +cairo_private cairo_compositor_t * +_cairo_gl_msaa_compositor_get (void); + cairo_private cairo_int_status_t _cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents, cairo_scaled_font_t *scaled_font, diff --git a/src/cairo-tristrip.c b/src/cairo-tristrip.c index bb4972f..57f8e68 100644 --- a/src/cairo-tristrip.c +++ b/src/cairo-tristrip.c @@ -37,6 +37,7 @@ #include "cairo-error-private.h" #include "cairo-tristrip-private.h" +#include "cairo-traps-private.h" void _cairo_tristrip_init (cairo_tristrip_t *strip) -- 1.7.4.1