diff options
-rw-r--r-- | boilerplate/cairo-boilerplate-cogl.c | 12 | ||||
-rw-r--r-- | src/Makefile.sources | 2 | ||||
-rw-r--r-- | src/cairo-cogl-context-private.h | 58 | ||||
-rw-r--r-- | src/cairo-cogl-context.c | 1063 | ||||
-rw-r--r-- | src/cairo-cogl-private.h | 17 | ||||
-rw-r--r-- | src/cairo-cogl-surface.c | 1133 | ||||
-rw-r--r-- | src/cairo-debug.c | 4 | ||||
-rw-r--r-- | src/meson.build | 1 |
8 files changed, 498 insertions, 1792 deletions
diff --git a/boilerplate/cairo-boilerplate-cogl.c b/boilerplate/cairo-boilerplate-cogl.c index c293b3932..2339dd883 100644 --- a/boilerplate/cairo-boilerplate-cogl.c +++ b/boilerplate/cairo-boilerplate-cogl.c @@ -119,12 +119,12 @@ _cairo_boilerplate_cogl_create_onscreen_color_surface (const char *name, height = 1; if (content & CAIRO_CONTENT_ALPHA) { - /* A hackish way to ensure that we get a framebuffer with - * an alpha component */ - CoglSwapChain *swap_chain; - CoglOnscreenTemplate *onscreen_template; - CoglRenderer *renderer; - CoglDisplay *display; + /* A hackish way to ensure that we get a framebuffer with + * an alpha component */ + CoglSwapChain *swap_chain; + CoglOnscreenTemplate *onscreen_template; + CoglRenderer *renderer; + CoglDisplay *display; swap_chain = cogl_swap_chain_new (); cogl_swap_chain_set_has_alpha (swap_chain, TRUE); diff --git a/src/Makefile.sources b/src/Makefile.sources index 096a3bcfa..2b573c8e5 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -468,9 +468,7 @@ cairo_vg_sources = cairo-vg-surface.c cairo_cogl_headers = cairo-cogl.h cairo_cogl_private = cairo-cogl-private.h \ cairo-cogl-gradient-private.h \ - cairo-cogl-context-private.h \ cairo-cogl-utils-private.h cairo_cogl_sources = cairo-cogl-surface.c \ cairo-cogl-gradient.c \ - cairo-cogl-context.c \ cairo-cogl-utils.c diff --git a/src/cairo-cogl-context-private.h b/src/cairo-cogl-context-private.h deleted file mode 100644 index a1b3152b1..000000000 --- a/src/cairo-cogl-context-private.h +++ /dev/null @@ -1,58 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2011 Intel Corporation. - * - * 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.og/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. - * - * Contributor(s): - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef CAIRO_COGL_CONTEXT_PRIVATE_H -#define CAIRO_COGL_CONTEXT_PRIVATE_H - -#include "cairo-default-context-private.h" -#include "cairo-cogl-private.h" - -typedef struct _cairo_cogl_context { - cairo_default_context_t base; - - int path_ctm_age; - cairo_path_fixed_t user_path; - - cairo_bool_t path_is_rectangle; - double x, y, width, height; - - cairo_backend_t backend; - - /* We save a copy of all the original backend methods that we override so - * we can chain up... - */ - cairo_backend_t backend_parent; -} cairo_cogl_context_t; - -cairo_t * -_cairo_cogl_context_create (void *target); - -#endif /* CAIRO_COGL_CONTEXT_PRIVATE_H */ diff --git a/src/cairo-cogl-context.c b/src/cairo-cogl-context.c deleted file mode 100644 index e0017dd9b..000000000 --- a/src/cairo-cogl-context.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2011 Intel Corporation. - * - * 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.og/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. - * - * Contributor(s): - * Robert Bragg <robert@linux.intel.com> - */ - -/* so long as we can verify that the ctm doesn't change multiple times - * during the construction of a path we can build a shadow - * #cairo_path_fixed_t in user coordinates that we can use to create a - * hash value for caching tessellations of that path. - * - * We need to hook into all the points where the ctm can be changed - * so we can bump a cr->path_ctm_age counter. - * - * We need to hook into all the points where the path can be modified - * so we can catch the start of a path and reset the cr->path_ctm_age - * counter at that point. - * - * When a draw operation is hit we can then check that the - * path_ctm_age == 0 and if so we create a hash of the path. - * - * We use this hash to lookup a #cairo_cogl_path_meta_t struct which - * may contain tessellated triangles for the path or may just contain - * a count of how many times the path has been re-seen (we only cache - * tessellated triangles if there is evidence that the path is being - * used multiple times because there is a cost involved in allocating - * a separate buffer for the triangles). - */ - -#include "cairoint.h" - -#include "cairo-cogl-context-private.h" -#include "cairo-freed-pool-private.h" -#include "cairo-arc-private.h" -#include "cairo-path-fixed-private.h" -#include "cairo-surface-subsurface-inline.h" - -#include <glib.h> - -static freed_pool_t context_pool; - -void -_cairo_cogl_context_reset_static_data (void) -{ - _freed_pool_reset (&context_pool); -} - -static cairo_status_t -_cairo_cogl_context_rectangle_real (cairo_cogl_context_t *cr, - double x, double y, - double width, double height) -{ - cairo_status_t status; - status = cr->backend_parent.rectangle (cr, x, y, width, height); - if (unlikely (status)) - return status; - - return _cairo_cogl_path_fixed_rectangle (&cr->user_path, - _cairo_fixed_from_double (x), - _cairo_fixed_from_double (y), - _cairo_fixed_from_double (width), - _cairo_fixed_from_double (height)); -} - -/* The idea here is that we have a simplified way of tracking rectangle paths - * because rectangles are perhaps the most common shape drawn with cairo. - * - * Basically we have a speculative store for a rectangle path that doesn't - * need to use the #cairo_path_fixed_t api to describe a rectangle in terms of - * (move_to,rel_line_to,rel_line_to,_rel_line_to,close) because if you profile - * heavy rectangle drawing with Cairo that process can be overly expensive. - * - * If the user asks to add more than just a rectangle to their current path - * then we "flush" any speculative rectangle stored into the current path - * before continuing to append their operations. - * - * In addition to the speculative store cairo-cogl also has a fast-path - * fill_rectangle drawing operation that further aims to minimize the cost - * of drawing rectangles. - */ -static cairo_status_t -_flush_cr_rectangle (cairo_cogl_context_t *cr) -{ - if (!cr->path_is_rectangle) - return CAIRO_STATUS_SUCCESS; - - cr->path_is_rectangle = FALSE; - return _cairo_cogl_context_rectangle_real (cr, cr->x, cr->y, cr->width, cr->height); -} - -static cairo_status_t -_cairo_cogl_context_restore (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.restore (abstract_cr); -} - -static cairo_status_t -_cairo_cogl_context_translate (void *abstract_cr, double tx, double ty) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.translate (abstract_cr, tx, ty); -} - -static cairo_status_t -_cairo_cogl_context_scale (void *abstract_cr, double sx, double sy) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.scale (abstract_cr, sx, sy); -} - -static cairo_status_t -_cairo_cogl_context_rotate (void *abstract_cr, double theta) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.rotate (abstract_cr, theta); -} - -static cairo_status_t -_cairo_cogl_context_transform (void *abstract_cr, - const cairo_matrix_t *matrix) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.transform (abstract_cr, matrix); -} - -static cairo_status_t -_cairo_cogl_context_set_matrix (void *abstract_cr, - const cairo_matrix_t *matrix) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.set_matrix (abstract_cr, matrix); -} - -static cairo_status_t -_cairo_cogl_context_set_identity_matrix (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - cr->path_ctm_age++; - return cr->backend_parent.set_identity_matrix (abstract_cr); -} - -static cairo_status_t -_cairo_cogl_context_new_path (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.new_path (abstract_cr); - if (unlikely (status)) - return status; - - _cairo_path_fixed_fini (&cr->user_path); - _cairo_path_fixed_init (&cr->user_path); - cr->path_is_rectangle = FALSE; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_new_sub_path (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.new_sub_path (abstract_cr); - if (unlikely (status)) - return status; - - _cairo_path_fixed_new_sub_path (&cr->user_path); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_move_to (void *abstract_cr, double x, double y) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t x_fixed, y_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.move_to (abstract_cr, x, y); - if (unlikely (status)) - return status; - - x_fixed = _cairo_fixed_from_double (x); - y_fixed = _cairo_fixed_from_double (y); - - return _cairo_path_fixed_move_to (&cr->user_path, x_fixed, y_fixed); -} - -static cairo_status_t -_cairo_cogl_context_line_to (void *abstract_cr, double x, double y) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t x_fixed, y_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.line_to (abstract_cr, x, y); - if (unlikely (status)) - return status; - - x_fixed = _cairo_fixed_from_double (x); - y_fixed = _cairo_fixed_from_double (y); - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - return _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed); -} - -static cairo_status_t -_cairo_cogl_context_curve_to (void *abstract_cr, - double x1, double y1, - double x2, double y2, - double x3, double y3) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t x1_fixed, y1_fixed; - cairo_fixed_t x2_fixed, y2_fixed; - cairo_fixed_t x3_fixed, y3_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3); - if (unlikely (status)) - return status; - - x1_fixed = _cairo_fixed_from_double (x1); - y1_fixed = _cairo_fixed_from_double (y1); - - x2_fixed = _cairo_fixed_from_double (x2); - y2_fixed = _cairo_fixed_from_double (y2); - - x3_fixed = _cairo_fixed_from_double (x3); - y3_fixed = _cairo_fixed_from_double (y3); - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - return _cairo_path_fixed_curve_to (&cr->user_path, - x1_fixed, y1_fixed, - x2_fixed, y2_fixed, - x3_fixed, y3_fixed); -} - -static cairo_status_t -_cairo_cogl_context_arc (void *abstract_cr, - double xc, - double yc, - double radius, - double angle1, - double angle2, - cairo_bool_t forward) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - /* Do nothing, successfully, if radius is <= 0 */ - if (radius <= 0.0) { - cairo_fixed_t x_fixed, y_fixed; - - x_fixed = _cairo_fixed_from_double (xc); - y_fixed = _cairo_fixed_from_double (yc); - status = _cairo_cogl_context_line_to (abstract_cr, - x_fixed, - y_fixed); - if (unlikely (status)) - return status; - - status = _cairo_cogl_context_line_to (abstract_cr, - x_fixed, - y_fixed); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; - } - - status = _cairo_cogl_context_line_to (cr, - xc + radius * cos (angle1), - yc + radius * sin (angle1)); - - if (unlikely (status)) - return status; - - /* These functions will be expressed in terms of the backend - * functions for line_to and curve_to, which we already add the - * appropriate segments to the user path in */ - if (forward) - _cairo_arc_path (&cr->base.base, - xc, - yc, - radius, - angle1, - angle2); - else - _cairo_arc_path_negative (&cr->base.base, - xc, - yc, - radius, - angle1, - angle2); - - /* any error will have already been set on cr */ - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_rel_move_to (void *abstract_cr, double dx, double dy) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t dx_fixed, dy_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.rel_move_to (abstract_cr, dx, dy); - if (unlikely (status)) - return status; - - dx_fixed = _cairo_fixed_from_double (dx); - dy_fixed = _cairo_fixed_from_double (dy); - - return _cairo_path_fixed_rel_move_to (&cr->user_path, dx_fixed, dy_fixed); -} - -static cairo_status_t -_cairo_cogl_context_rel_line_to (void *abstract_cr, double dx, double dy) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t dx_fixed, dy_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.rel_line_to (abstract_cr, dx, dy); - if (unlikely (status)) - return status; - - dx_fixed = _cairo_fixed_from_double (dx); - dy_fixed = _cairo_fixed_from_double (dy); - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - return _cairo_path_fixed_rel_line_to (&cr->user_path, dx_fixed, dy_fixed); -} - - -static cairo_status_t -_cairo_cogl_context_rel_curve_to (void *abstract_cr, - double dx1, double dy1, - double dx2, double dy2, - double dx3, double dy3) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_fixed_t dx1_fixed, dy1_fixed; - cairo_fixed_t dx2_fixed, dy2_fixed; - cairo_fixed_t dx3_fixed, dy3_fixed; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3); - if (unlikely (status)) - return status; - - dx1_fixed = _cairo_fixed_from_double (dx1); - dy1_fixed = _cairo_fixed_from_double (dy1); - - dx2_fixed = _cairo_fixed_from_double (dx2); - dy2_fixed = _cairo_fixed_from_double (dy2); - - dx3_fixed = _cairo_fixed_from_double (dx3); - dy3_fixed = _cairo_fixed_from_double (dy3); - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - return _cairo_path_fixed_rel_curve_to (&cr->user_path, - dx1_fixed, dy1_fixed, - dx2_fixed, dy2_fixed, - dx3_fixed, dy3_fixed); -} - -#if 0 -static cairo_status_t -_cairo_cogl_context_arc_to (void *abstract_cr, - double x1, double y1, - double x2, double y2, - double radius) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius); - if (unlikely (status)) - return status; -#warning "FIXME" -} - -static cairo_status_t -_cairo_cogl_rel_arc_to (void *cr, - double dx1, double dy1, - double dx2, double dy2, - double radius) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius); - if (unlikely (status)) - return status; -#warning "FIXME" -} -#endif - -static cairo_status_t -_cairo_cogl_context_close_path (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - status = cr->backend_parent.close_path (abstract_cr); - if (unlikely (status)) - return status; - - if (cr->user_path.buf.base.num_ops == 0) - cr->path_ctm_age = 0; - - return _cairo_path_fixed_close_path (&cr->user_path); -} - -static cairo_status_t -_cairo_cogl_context_rectangle (void *abstract_cr, - double x, double y, - double width, double height) -{ - cairo_cogl_context_t *cr = abstract_cr; - - /* Do not take the single-rectangle shortcut if we already have a - * path, whether conventional or rectangle */ - if (cr->user_path.buf.base.num_ops == 0 && !cr->path_is_rectangle) { - cr->path_ctm_age = 0; - -#if 1 - /* XXX: Since drawing rectangles is so common we have a - * fast-path for drawing a single rectangle. */ - cr->x = x; - cr->y = y; - cr->width = width; - cr->height = height; - cr->path_is_rectangle = TRUE; - cr->base.path->fill_is_empty = FALSE; - return CAIRO_STATUS_SUCCESS; -#endif - } - - if (cr->path_is_rectangle) { - cairo_status_t status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - return _cairo_cogl_context_rectangle_real (cr, x, y, width, height); -} - -static void -_cairo_cogl_context_path_extents (void *abstract_cr, - double *x1, - double *y1, - double *x2, - double *y2) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) - assert (_flush_cr_rectangle (cr) == CAIRO_STATUS_SUCCESS); - - cr->backend_parent.path_extents (abstract_cr, x1, y1, x2, y2); -} - -static cairo_bool_t -_cairo_cogl_context_has_current_point (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) - assert (_flush_cr_rectangle (cr) == CAIRO_STATUS_SUCCESS); - - return cr->backend_parent.has_current_point (abstract_cr); -} - -static cairo_bool_t -_cairo_cogl_context_get_current_point (void *abstract_cr, - double *x, - double *y) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) - assert (_flush_cr_rectangle (cr) == CAIRO_STATUS_SUCCESS); - - return cr->backend_parent.get_current_point (abstract_cr, x, y); -} - -static cairo_path_t * -_cairo_cogl_context_copy_path (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) - assert (_flush_cr_rectangle (cr) == CAIRO_STATUS_SUCCESS); - - return cr->backend_parent.copy_path (abstract_cr); -} - -static cairo_path_t * -_cairo_cogl_context_copy_path_flat (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - if (cr->path_is_rectangle) - assert (_flush_cr_rectangle (cr) == CAIRO_STATUS_SUCCESS); - - return cr->backend_parent.copy_path_flat (abstract_cr); -} - -static cairo_status_t -_cairo_cogl_context_append_path (void *abstract_cr, - const cairo_path_t *path) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - return cr->backend_parent.append_path (abstract_cr, path); -} - -/* Since the surface backend drawing operator functions don't get - * passed the current #cairo_t context we don't have a good way - * to get our user-coordinates path into our surface operator - * functions. - * - * For now we use this function to set side band data on the surface - * itself. - */ -static void -_cairo_cogl_surface_set_side_band_state (cairo_cogl_surface_t *surface, - cairo_cogl_context_t *cr) -{ - cairo_gstate_t *gstate = cr->base.gstate; - - if (cr->path_ctm_age == 0) { - surface->user_path = &cr->user_path; - cairo_matrix_multiply (&surface->ctm, - &gstate->ctm, - &gstate->target->device_transform); - cairo_matrix_multiply (&surface->ctm_inverse, - &gstate->target->device_transform_inverse, - &gstate->ctm_inverse); - surface->path_is_rectangle = cr->path_is_rectangle; - if (surface->path_is_rectangle) { - surface->path_rectangle_x = cr->x; - surface->path_rectangle_y = cr->y; - surface->path_rectangle_width = cr->width; - surface->path_rectangle_height = cr->height; - } - } else { - surface->user_path = NULL; - surface->path_is_rectangle = FALSE; - } -} - -static cairo_cogl_surface_t * -_cairo_cogl_get_cogl_surface (cairo_surface_t *target) -{ - /* Subsurfaces are always 1-depth */ - if (_cairo_surface_is_subsurface (target)) - target = _cairo_surface_subsurface_get_target (target); - - if (target->type == CAIRO_SURFACE_TYPE_COGL) - return (cairo_cogl_surface_t *)target; - else - /* return NULL if the target is not a cogl surface */ - return NULL; -} - -static cairo_status_t -_cairo_cogl_context_fill (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - if (cr->path_is_rectangle) { - if (surface) { - cairo_matrix_t ctm; - - status = - _cairo_surface_begin_modification (cr->base.gstate->target); - if (status) - return status; - - ctm = cr->base.gstate->ctm; - if (_cairo_surface_is_subsurface (cr->base.gstate->target)) - cairo_matrix_translate (&ctm, - ((cairo_surface_subsurface_t *)cr->base.gstate->target)->extents.x, - ((cairo_surface_subsurface_t *)cr->base.gstate->target)->extents.y); - - status = _cairo_cogl_surface_fill_rectangle ((cairo_surface_t *)surface, - cr->base.gstate->op, - cr->base.gstate->source, - cr->x, - cr->y, - cr->width, - cr->height, - &ctm, - cr->base.gstate->clip); - if (status == CAIRO_STATUS_SUCCESS) - goto DONE; - } - - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.fill (abstract_cr); - if (unlikely (status)) - return status; - -DONE: - _cairo_path_fixed_fini (&cr->user_path); - _cairo_path_fixed_init (&cr->user_path); - cr->path_is_rectangle = FALSE; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_fill_preserve (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - if (cr->path_is_rectangle) { - if (surface) { - cairo_matrix_t ctm; - - status = - _cairo_surface_begin_modification (cr->base.gstate->target); - if (status) - return status; - - ctm = cr->base.gstate->ctm; - if (_cairo_surface_is_subsurface (cr->base.gstate->target)) - cairo_matrix_translate (&ctm, - ((cairo_surface_subsurface_t *)cr->base.gstate->target)->extents.x, - ((cairo_surface_subsurface_t *)cr->base.gstate->target)->extents.y); - - status = _cairo_cogl_surface_fill_rectangle ((cairo_surface_t *)surface, - cr->base.gstate->op, - cr->base.gstate->source, - cr->x, - cr->y, - cr->width, - cr->height, - &ctm, - cr->base.gstate->clip); - if (status == CAIRO_STATUS_SUCCESS) - goto DONE; - } - - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.fill_preserve (abstract_cr); - if (unlikely (status)) - return status; - -DONE: - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_stroke (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - /* This operator can't use an accelerated rectangle path yet */ - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.stroke (abstract_cr); - if (unlikely (status)) - return status; - - _cairo_path_fixed_fini (&cr->user_path); - _cairo_path_fixed_init (&cr->user_path); - cr->path_is_rectangle = FALSE; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_stroke_preserve (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - /* This operator can't use an accelerated rectangle path yet */ - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.stroke_preserve (abstract_cr); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_clip (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - /* This operator can't use an accelerated rectangle path yet */ - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.clip (abstract_cr); - if (unlikely (status)) - return status; - - _cairo_path_fixed_fini (&cr->user_path); - _cairo_path_fixed_init (&cr->user_path); - cr->path_is_rectangle = FALSE; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_cogl_context_clip_preserve (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - cairo_status_t status; - cairo_cogl_surface_t *surface = - _cairo_cogl_get_cogl_surface (cr->base.gstate->target); - - /* This operator can't use an accelerated rectangle path yet */ - if (cr->path_is_rectangle) { - status = _flush_cr_rectangle (cr); - if (unlikely (status)) - return status; - } - - if (surface) - _cairo_cogl_surface_set_side_band_state (surface, cr); - - status = cr->backend_parent.clip_preserve (abstract_cr); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_cogl_context_destroy (void *abstract_cr) -{ - cairo_cogl_context_t *cr = abstract_cr; - - _cairo_default_context_fini (&cr->base); - - _cairo_path_fixed_fini (&cr->user_path); - - /* mark the context as invalid to protect against misuse */ - cr->base.base.status = CAIRO_STATUS_NULL_POINTER; - _freed_pool_put (&context_pool, cr); -} - -void -_cairo_cogl_context_set_custom_vtable_funcs (cairo_backend_t *backend); - -/* We want to hook into the frontend of the path construction APIs so - * we can build up a path description in user coordinates instead of - * backend coordinates so that we can recognize user coordinate - * rectangles and so we can hash a user path independent of its - * transform. (With some care to catch unusual cases where the ctm - * changes mid-path) */ -cairo_t * -_cairo_cogl_context_create (void *target) -{ - cairo_cogl_context_t *cr; - cairo_status_t status; - - cr = _freed_pool_get (&context_pool); - if (unlikely (cr == NULL)) { - cr = _cairo_malloc (sizeof (cairo_cogl_context_t)); - if (unlikely (cr == NULL)) - return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - status = _cairo_default_context_init (&cr->base, target); - if (unlikely (status)) { - _freed_pool_put (&context_pool, cr); - return _cairo_create_in_error (status); - } - - memcpy (&cr->backend, cr->base.base.backend, sizeof (cairo_backend_t)); - memcpy (&cr->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t)); - - _cairo_cogl_context_set_custom_vtable_funcs (&cr->backend); - - cr->base.base.backend = &cr->backend; - - _cairo_path_fixed_init (&cr->user_path); - cr->path_is_rectangle = FALSE; - cr->path_ctm_age = 0; - - return &cr->base.base; -} - -void -_cairo_cogl_context_set_custom_vtable_funcs (cairo_backend_t *backend) -{ - backend->destroy = _cairo_cogl_context_destroy; - - backend->restore = _cairo_cogl_context_restore; - - backend->translate = _cairo_cogl_context_translate; - backend->scale = _cairo_cogl_context_scale; - backend->rotate = _cairo_cogl_context_rotate; - backend->transform = _cairo_cogl_context_transform; - backend->set_matrix = _cairo_cogl_context_set_matrix; - backend->set_identity_matrix = _cairo_cogl_context_set_identity_matrix; - - backend->new_path = _cairo_cogl_context_new_path; - backend->new_sub_path = _cairo_cogl_context_new_sub_path; - backend->move_to = _cairo_cogl_context_move_to; - backend->rel_move_to = _cairo_cogl_context_rel_move_to; - backend->line_to = _cairo_cogl_context_line_to; - backend->rel_line_to = _cairo_cogl_context_rel_line_to; - backend->curve_to = _cairo_cogl_context_curve_to; - backend->rel_curve_to = _cairo_cogl_context_rel_curve_to; -#if 0 - backend->arc_to = _cairo_cogl_context_arc_to; - backend->rel_arc_to = _cairo_cogl_context_rel_arc_to; -#endif - backend->close_path = _cairo_cogl_context_close_path; - backend->arc = _cairo_cogl_context_arc; - backend->rectangle = _cairo_cogl_context_rectangle; - backend->path_extents = _cairo_cogl_context_path_extents; - backend->has_current_point = _cairo_cogl_context_has_current_point; - backend->get_current_point = _cairo_cogl_context_get_current_point; - backend->copy_path = _cairo_cogl_context_copy_path; - backend->copy_path_flat = _cairo_cogl_context_copy_path_flat; - backend->append_path = _cairo_cogl_context_append_path; - - /* Try to automatically catch if any new path APIs are added that - * mean we may need to overload more functions... */ - assert (((char *)&backend->clip - - (char *)&backend->backend_to_user_distance) - == (sizeof (void *) * 21)); - - backend->fill = _cairo_cogl_context_fill; - backend->fill_preserve = _cairo_cogl_context_fill_preserve; - backend->stroke = _cairo_cogl_context_stroke; - backend->stroke_preserve = _cairo_cogl_context_stroke_preserve; - backend->clip = _cairo_cogl_context_clip; - backend->clip_preserve = _cairo_cogl_context_clip_preserve; -} diff --git a/src/cairo-cogl-private.h b/src/cairo-cogl-private.h index 3f7b3693e..b0be2661e 100644 --- a/src/cairo-cogl-private.h +++ b/src/cairo-cogl-private.h @@ -37,6 +37,7 @@ #include "cairo-backend-private.h" #include "cairo-default-context-private.h" #include "cairo-surface-private.h" +#include "cairo-freelist-private.h" #include <cogl/cogl2-experimental.h> @@ -93,10 +94,11 @@ typedef struct _cairo_cogl_device { /* Caches 1d linear gradient textures */ cairo_cache_t linear_cache; - cairo_cache_t path_fill_staging_cache; cairo_cache_t path_fill_prim_cache; - cairo_cache_t path_stroke_staging_cache; cairo_cache_t path_stroke_prim_cache; + + cairo_freelist_t path_fill_meta_freelist; + cairo_freelist_t path_stroke_meta_freelist; } cairo_cogl_device_t; typedef struct _cairo_cogl_clip_primitives { @@ -159,15 +161,4 @@ _cairo_cogl_path_fixed_rectangle (cairo_path_fixed_t *path, cairo_fixed_t width, cairo_fixed_t height); -cairo_int_status_t -_cairo_cogl_surface_fill_rectangle (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - double x, - double y, - double width, - double height, - cairo_matrix_t *ctm, - const cairo_clip_t *clip); - #endif /* CAIRO_COGL_PRIVATE_H */ diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c index f1f091bad..fce03db5d 100644 --- a/src/cairo-cogl-surface.c +++ b/src/cairo-cogl-surface.c @@ -43,7 +43,6 @@ #include "cairo-cogl-gradient-private.h" #include "cairo-arc-private.h" #include "cairo-traps-private.h" -#include "cairo-cogl-context-private.h" #include "cairo-cogl-utils-private.h" #include "cairo-surface-subsurface-inline.h" #include "cairo-surface-fallback-private.h" @@ -57,15 +56,8 @@ #define CAIRO_COGL_DEBUG 0 //#define FILL_WITH_COGL_PATH //#define USE_CAIRO_PATH_FLATTENER -#define ENABLE_PATH_CACHE //#define DISABLE_BATCHING #define MAX_JOURNAL_SIZE 100 -#define ENABLE_RECTANGLES_FASTPATH -//#define ENABLE_CLIP_CACHE // This hasn't been implemented yet - -#if defined (ENABLE_RECTANGLES_FASTPATH) || defined (ENABLE_PATH_CACHE) -#define NEED_COGL_CONTEXT -#endif #if CAIRO_COGL_DEBUG && __GNUC__ #define UNSUPPORTED(reason) ({ \ @@ -139,7 +131,6 @@ typedef struct _cairo_cogl_journal_prim_entry { cairo_cogl_pipeline_t *pipeline; CoglPrimitive *primitive; - cairo_bool_t has_transform; cairo_matrix_t transform; } cairo_cogl_journal_prim_entry_t; @@ -151,49 +142,25 @@ typedef struct _cairo_cogl_journal_path_entry { } cairo_cogl_journal_path_entry_t; typedef struct _cairo_cogl_path_fill_meta { - cairo_cache_entry_t cache_entry; - cairo_reference_count_t ref_count; - int counter; - cairo_path_fixed_t *user_path; - cairo_matrix_t ctm_inverse; - - /* TODO */ -#if 0 - /* A cached path tessellation should be re-usable with different rotations - * and translations but not for different scales. - * - * one idea is to track the diagonal lengths of a unit rectangle - * transformed through the original ctm use to tessellate the geometry - * so we can check what the lengths are for any new ctm to know if - * this geometry is compatible. - */ -#endif + cairo_cache_entry_t base; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; CoglPrimitive *prim; + + cairo_freelist_t *freelist; } cairo_cogl_path_fill_meta_t; typedef struct _cairo_cogl_path_stroke_meta { - cairo_cache_entry_t cache_entry; - cairo_reference_count_t ref_count; - int counter; - cairo_path_fixed_t *user_path; - cairo_matrix_t ctm_inverse; + cairo_cache_entry_t base; + cairo_path_fixed_t path; cairo_stroke_style_t style; double tolerance; - /* TODO */ -#if 0 - /* A cached path tessellation should be re-usable with different rotations - * and translations but not for different scales. - * - * one idea is to track the diagonal lengths of a unit rectangle - * transformed through the original ctm use to tessellate the geometry - * so we can check what the lengths are for any new ctm to know if - * this geometry is compatible. - */ -#endif - CoglPrimitive *prim; + + cairo_freelist_t *freelist; } cairo_cogl_path_stroke_meta_t; static cairo_surface_t * @@ -449,12 +416,7 @@ _cairo_cogl_journal_log_primitive (cairo_cogl_surface_t *surface, if (primitive) cogl_object_ref (primitive); - if (transform) { - entry->transform = *transform; - entry->has_transform = TRUE; - } else { - entry->has_transform = FALSE; - } + entry->transform = *transform; g_queue_push_tail (surface->journal, entry); @@ -623,11 +585,11 @@ _cairo_cogl_traps_to_triangles_buffer (cairo_cogl_surface_t *surface, p[2].x = _cairo_cogl_util_fixed_to_float (trap->right.p2.x); p[2].y = _cairo_cogl_util_fixed_to_float (trap->right.p2.y); - p[3].x = _cairo_cogl_util_fixed_to_float (trap->left.p1.x); - p[3].y = _cairo_cogl_util_fixed_to_float (trap->left.p1.y); + p[3].x = p[0].x; + p[3].y = p[0].y; - p[4].x = _cairo_cogl_util_fixed_to_float (trap->right.p2.x); - p[4].y = _cairo_cogl_util_fixed_to_float (trap->right.p2.y); + p[4].x = p[2].x; + p[4].y = p[2].y; p[5].x = _cairo_cogl_util_fixed_to_float (trap->right.p1.x); p[5].y = _cairo_cogl_util_fixed_to_float (trap->right.p1.y); @@ -699,6 +661,87 @@ _cairo_cogl_traps_to_composite_prim (cairo_cogl_surface_t *surface, return prim; } +/* In order to facilitate path caching, we transform the input path + * into a form that will make all translations and rotations of a given + * path identical, thereby allowing them to be identified with + * conventional path hashing and equivalence functions. A + * transformation matrix is also output so that the path can be + * transformed back into its original form during rendering. */ +static cairo_int_status_t +_cairo_cogl_get_untransformed_path (cairo_path_fixed_t *copy, + const cairo_path_fixed_t *orig, + cairo_matrix_t *transform_out) +{ + cairo_matrix_t transform; + cairo_int_status_t status; + + if (orig->buf.base.num_points < 1) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + status = _cairo_path_fixed_init_copy (copy, orig); + if (unlikely (status)) + return status; + + /* First the path is translated so that its first point lies on the + * origin. */ + cairo_matrix_init_translate (&transform, + -_cairo_fixed_to_double(orig->buf.points[0].x), + -_cairo_fixed_to_double(orig->buf.points[0].y)); + + /* Then the path is rotated so that its second point lies on the + * x axis. */ + if (orig->buf.base.num_points > 1) { + double x = _cairo_fixed_to_double(orig->buf.points[1].x) - + _cairo_fixed_to_double(orig->buf.points[0].x); + double y = _cairo_fixed_to_double(orig->buf.points[1].y) - + _cairo_fixed_to_double(orig->buf.points[0].y); + double hyp = sqrt (x * x + y * y); + + transform.xx = x / hyp; + transform.yy = x / hyp; + transform.xy = -y / hyp; + transform.yx = y / hyp; + } + + _cairo_path_fixed_transform (copy, &transform); + + *transform_out = transform; + status = cairo_matrix_invert (transform_out); + if (unlikely (status)) { + _cairo_path_fixed_fini (copy); + return status; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static void +_cairo_cogl_path_fill_meta_destroy (cairo_cogl_path_fill_meta_t *meta) +{ + _cairo_path_fixed_fini (&meta->path); + cogl_object_unref (meta->prim); + + _cairo_freelist_free (meta->freelist, meta); +} + +static cairo_bool_t +_cairo_cogl_path_fill_meta_equal (const void *key_a, const void *key_b) +{ + const cairo_cogl_path_fill_meta_t *meta0 = key_a; + const cairo_cogl_path_fill_meta_t *meta1 = key_b; + + if (meta0->fill_rule != meta1->fill_rule) + return FALSE; + + if (meta0->tolerance != meta1->tolerance) + return FALSE; + + if (!_cairo_path_fixed_equal (&meta0->path, &meta1->path)) + return FALSE; + + return TRUE; +} + static cairo_int_status_t _cairo_cogl_fill_to_primitive (cairo_cogl_surface_t *surface, const cairo_path_fixed_t *path, @@ -706,13 +749,46 @@ _cairo_cogl_fill_to_primitive (cairo_cogl_surface_t *surface, double tolerance, cairo_bool_t one_shot, CoglPrimitive **primitive, - size_t *size) + cairo_matrix_t *transform) { cairo_traps_t traps; cairo_int_status_t status; + cairo_cogl_path_fill_meta_t meta; + cairo_cogl_path_fill_meta_t *acquired_meta; + cairo_cogl_path_fill_meta_t *insert_meta = NULL; + cairo_cogl_device_t *dev = to_device (surface->base.device); + unsigned long hash; + + *primitive = NULL; + + status = _cairo_cogl_get_untransformed_path (&meta.path, + path, + transform); + if (unlikely (status)) + return status; + + hash = _cairo_path_fixed_hash (&meta.path); + hash = _cairo_hash_bytes (hash, &fill_rule, sizeof (fill_rule)); + hash = _cairo_hash_bytes (hash, &tolerance, sizeof (tolerance)); + meta.base.hash = hash; + meta.tolerance = tolerance; + meta.fill_rule = fill_rule; + + acquired_meta = _cairo_cache_lookup (&dev->path_fill_prim_cache, + &meta.base); + + if (acquired_meta) { + // g_print ("fill cache hit"); + *primitive = cogl_object_ref (acquired_meta->prim); + _cairo_path_fixed_fini (&meta.path); + return CAIRO_STATUS_SUCCESS; + } _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); + status = _cairo_path_fixed_fill_to_traps (&meta.path, + fill_rule, + tolerance, + &traps); if (unlikely (status)) goto BAIL; @@ -721,16 +797,249 @@ _cairo_cogl_fill_to_primitive (cairo_cogl_surface_t *surface, goto BAIL; } - *size = traps.num_traps * sizeof (CoglVertexP2) * 6; + *primitive = _cairo_cogl_traps_to_composite_prim (surface, + &traps, + one_shot); + if (unlikely (!*primitive)) { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto BAIL; + } + + insert_meta = + _cairo_freelist_alloc (&dev->path_fill_meta_freelist); + if (unlikely (!insert_meta)) { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto BAIL; + } + + insert_meta->base.hash = meta.base.hash; + insert_meta->base.size = + traps.num_traps * sizeof (CoglVertexP2) * 6; + insert_meta->tolerance = tolerance; + insert_meta->fill_rule = fill_rule; + insert_meta->prim = cogl_object_ref (*primitive); + insert_meta->freelist = &dev->path_fill_meta_freelist; + + status = _cairo_path_fixed_init_copy (&insert_meta->path, + &meta.path); + if (unlikely (status)) + goto BAIL; + + if (unlikely (_cairo_cache_insert (&dev->path_fill_prim_cache, + &insert_meta->base))) + { + g_warning ("Fill primitive cache insertion unsuccessful"); + goto BAIL; + } + + _cairo_path_fixed_fini (&meta.path); + _cairo_traps_fini (&traps); + + return status; + +BAIL: + if (*primitive) { + cogl_object_unref (*primitive); + *primitive = NULL; + } + if (insert_meta) + _cairo_cogl_path_fill_meta_destroy (insert_meta); + _cairo_path_fixed_fini (&meta.path); + _cairo_traps_fini (&traps); + + return status; +} + +static cairo_bool_t +_cairo_cogl_stroke_style_equal (const cairo_stroke_style_t *a, + const cairo_stroke_style_t *b) +{ + if (a->line_width == b->line_width && + a->line_cap == b->line_cap && + a->line_join == b->line_join && + a->miter_limit == b->miter_limit && + a->num_dashes == b->num_dashes && + a->dash_offset == b->dash_offset) + { + unsigned int i; + for (i = 0; i < a->num_dashes; i++) { + if (a->dash[i] != b->dash[i]) + return FALSE; + } + } + return TRUE; +} + +static cairo_bool_t +_cairo_cogl_path_stroke_meta_equal (const void *key_a, + const void *key_b) +{ + const cairo_cogl_path_stroke_meta_t *meta0 = key_a; + const cairo_cogl_path_stroke_meta_t *meta1 = key_b; + + if (meta0->tolerance != meta1->tolerance) + return FALSE; + + if (!_cairo_cogl_stroke_style_equal (&meta0->style, &meta1->style)) + return FALSE; + + if (!_cairo_path_fixed_equal (&meta0->path, &meta1->path)) + return FALSE; - *primitive = _cairo_cogl_traps_to_composite_prim (surface, &traps, one_shot); + return TRUE; +} + +static void +_cairo_cogl_path_stroke_meta_destroy (cairo_cogl_path_stroke_meta_t *meta) +{ + _cairo_stroke_style_fini (&meta->style); + _cairo_path_fixed_fini (&meta->path); + cogl_object_unref (meta->prim); + + _cairo_freelist_free (meta->freelist, meta); +} + +static unsigned long +_cairo_cogl_stroke_style_hash (unsigned long hash, + const cairo_stroke_style_t *style) +{ + unsigned int i; + hash = _cairo_hash_bytes (hash, &style->line_width, sizeof (style->line_width)); + hash = _cairo_hash_bytes (hash, &style->line_cap, sizeof (style->line_cap)); + hash = _cairo_hash_bytes (hash, &style->line_join, sizeof (style->line_join)); + hash = _cairo_hash_bytes (hash, &style->miter_limit, sizeof (style->miter_limit)); + hash = _cairo_hash_bytes (hash, &style->num_dashes, sizeof (style->num_dashes)); + hash = _cairo_hash_bytes (hash, &style->dash_offset, sizeof (style->dash_offset)); + for (i = 0; i < style->num_dashes; i++) + hash = _cairo_hash_bytes (hash, &style->dash[i], sizeof (double)); + return hash; +} + +static cairo_int_status_t +_cairo_cogl_stroke_to_primitive (cairo_cogl_surface_t *surface, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + double tolerance, + cairo_bool_t one_shot, + CoglPrimitive **primitive, + cairo_matrix_t *transform) +{ + cairo_traps_t traps; + cairo_int_status_t status; + cairo_cogl_path_stroke_meta_t meta; + cairo_cogl_path_stroke_meta_t *acquired_meta; + cairo_cogl_path_stroke_meta_t *insert_meta = NULL; + cairo_matrix_t identity; + cairo_cogl_device_t *dev = to_device (surface->base.device); + unsigned long hash; + + *primitive = NULL; + + status = _cairo_cogl_get_untransformed_path (&meta.path, + path, + transform); + if (unlikely (status)) + return status; + + hash = _cairo_path_fixed_hash (&meta.path); + hash = _cairo_cogl_stroke_style_hash (hash, style); + hash = _cairo_hash_bytes (hash, &tolerance, sizeof (tolerance)); + meta.base.hash = hash; + meta.tolerance = tolerance; + + status = _cairo_stroke_style_init_copy (&meta.style, style); + if (unlikely (status)) { + _cairo_path_fixed_fini (&meta.path); + return status; + } + + acquired_meta = _cairo_cache_lookup (&dev->path_stroke_prim_cache, + &meta.base); + + if (acquired_meta) { + // g_print ("stroke cache hit"); + *primitive = cogl_object_ref (acquired_meta->prim); + _cairo_path_fixed_fini (&meta.path); + return CAIRO_STATUS_SUCCESS; + } + + _cairo_traps_init (&traps); + + cairo_matrix_init_identity (&identity); + status = _cairo_path_fixed_stroke_polygon_to_traps (&meta.path, + style, + &identity, + &identity, + tolerance, + &traps); + if (unlikely (status)) + goto BAIL; + + if (traps.num_traps == 0) { + status = CAIRO_INT_STATUS_NOTHING_TO_DO; + goto BAIL; + } + + *primitive = _cairo_cogl_traps_to_composite_prim (surface, + &traps, + one_shot); if (unlikely (!*primitive)) { status = CAIRO_INT_STATUS_NO_MEMORY; goto BAIL; } + insert_meta = + _cairo_freelist_alloc (&dev->path_stroke_meta_freelist); + if (unlikely (!insert_meta)) { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto BAIL; + } + + insert_meta->base.hash = meta.base.hash; + insert_meta->base.size = + traps.num_traps * sizeof (CoglVertexP2) * 6; + insert_meta->tolerance = tolerance; + insert_meta->prim = cogl_object_ref (*primitive); + insert_meta->freelist = &dev->path_stroke_meta_freelist; + + status = _cairo_stroke_style_init_copy (&insert_meta->style, + style); + if (unlikely (status)) { + _cairo_stroke_style_fini (&insert_meta->style); + free (insert_meta); + insert_meta = NULL; + goto BAIL; + } + + status = _cairo_path_fixed_init_copy (&insert_meta->path, + &meta.path); + if (unlikely (status)) + goto BAIL; + + if (unlikely (_cairo_cache_insert (&dev->path_stroke_prim_cache, + &insert_meta->base))) + { + g_warning ("Stroke primitive cache insertion unsuccessful"); + goto BAIL; + } + + _cairo_path_fixed_fini (&meta.path); + _cairo_stroke_style_fini (&meta.style); + _cairo_traps_fini (&traps); + + return status; + BAIL: + if (*primitive) { + cogl_object_unref (*primitive); + *primitive = NULL; + } + if (insert_meta) + _cairo_cogl_path_stroke_meta_destroy (insert_meta); + _cairo_path_fixed_fini (&meta.path); + _cairo_stroke_style_fini (&meta.style); _cairo_traps_fini (&traps); + return status; } @@ -744,20 +1053,9 @@ _cairo_cogl_set_path_prim_clip (cairo_cogl_surface_t *surface, cairo_rectangle_int_t extents; cairo_int_status_t status; CoglPrimitive *prim; - size_t prim_size; - - _cairo_path_fixed_approximate_clip_extents (path, &extents); - - /* TODO - maintain a fifo of the last 10 used clips with cached - * primitives to see if we can avoid tessellating the path and - * uploading the vertices... - */ -#ifdef ENABLE_CLIP_CACHE - prim = NULL; - prim = find_clip_path_primitive (path); - if (prim) - // then bypass filling -#endif + cairo_matrix_t transform; + CoglMatrix matrix; + double x1, y1, x2, y2; status = _cairo_cogl_fill_to_primitive (surface, path, @@ -765,7 +1063,7 @@ _cairo_cogl_set_path_prim_clip (cairo_cogl_surface_t *surface, tolerance, FALSE, &prim, - &prim_size); + &transform); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { /* If the clip is of zero fill area, set all clipped */ cogl_framebuffer_push_scissor_clip (surface->framebuffer, @@ -773,16 +1071,50 @@ _cairo_cogl_set_path_prim_clip (cairo_cogl_surface_t *surface, (*clip_stack_depth)++; return; } else if (unlikely (status)) { - g_warning ("Failed to get primitive for clip path while flushing journal"); + g_warning ("Failed to get primitive for clip path while " + "flushing journal"); goto BAIL; } + float transformfv[16] = { + transform.xx, transform.yx, 0, 0, + transform.xy, transform.yy, 0, 0, + 0, 0, 1, 0, + transform.x0, transform.y0, 0, 1 + }; + + cogl_matrix_init_from_array (&matrix, transformfv); + + cogl_framebuffer_push_matrix (surface->framebuffer); + cogl_framebuffer_transform (surface->framebuffer, &matrix); + + _cairo_path_fixed_approximate_clip_extents (path, &extents); + + /* The extents need to be transformed by the inverse of the + * modelview matrix because they are in terms of un-transformed + * device coordinates and the bounds coordinates will be + * transformed by the modelview matrix */ + status = cairo_matrix_invert (&transform); + if (unlikely (status)) { + g_warning ("Could not apply clip due to invalid matrix from " + "path transformation"); + goto BAIL; + } + + x1 = extents.x; + y1 = extents.y; + x2 = extents.x + extents.width; + y2 = extents.y + extents.height; + _cairo_matrix_transform_bounding_box (&transform, + &x1, &y1, &x2, &y2, + NULL); + cogl_framebuffer_push_primitive_clip (surface->framebuffer, prim, - extents.x, extents.y, - extents.x + extents.width, - extents.y + extents.height); + x1, y1, x2, y2); (*clip_stack_depth)++; + cogl_framebuffer_pop_matrix (surface->framebuffer); + BAIL: if (prim) cogl_object_unref (prim); @@ -1158,20 +1490,15 @@ _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface) prim_entry->pipeline); cogl_framebuffer_push_matrix (surface->framebuffer); - if (prim_entry->has_transform) { - cairo_matrix_t *ctm = &prim_entry->transform; - float ctmfv[16] = { - ctm->xx, ctm->yx, 0, 0, - ctm->xy, ctm->yy, 0, 0, - 0, 0, 1, 0, - ctm->x0, ctm->y0, 0, 1 - }; - cogl_matrix_init_from_array (&transform, ctmfv); - cogl_framebuffer_transform (surface->framebuffer, &transform); - } else { - cogl_matrix_init_identity (&transform); - cogl_framebuffer_set_modelview_matrix (surface->framebuffer, &transform); - } + cairo_matrix_t *ctm = &prim_entry->transform; + float ctmfv[16] = { + ctm->xx, ctm->yx, 0, 0, + ctm->xy, ctm->yy, 0, 0, + 0, 0, 1, 0, + ctm->x0, ctm->y0, 0, 1 + }; + cogl_matrix_init_from_array (&transform, ctmfv); + cogl_framebuffer_transform (surface->framebuffer, &transform); /* If the primitive is NULL, it means we just draw the * unbounded rectangle */ @@ -2702,8 +3029,11 @@ static void set_layer_texture_with_attributes (CoglPipeline *pipeline, int layer_index, CoglTexture *texture, - cairo_cogl_texture_attributes_t *attributes) + cairo_cogl_texture_attributes_t *attributes, + cairo_matrix_t *path_transform) { + cairo_matrix_t m; + cogl_pipeline_set_layer_texture (pipeline, layer_index, texture); cogl_pipeline_set_layer_filters (pipeline, @@ -2711,13 +3041,20 @@ set_layer_texture_with_attributes (CoglPipeline *pipeline, attributes->filter, attributes->filter); - if (!_cairo_matrix_is_identity (&attributes->matrix)) { - cairo_matrix_t *m = &attributes->matrix; + /* We multiply in the path transform here so that we read texture + * values from coordinates that are consistent with the coordinates + * of the path after it is transformed by the modelview matrix */ + if (path_transform) + cairo_matrix_multiply (&m, path_transform, &attributes->matrix); + else + m = attributes->matrix; + + if (!_cairo_matrix_is_identity (&m)) { float texture_matrixfv[16] = { - m->xx, m->yx, 0, 0, - m->xy, m->yy, 0, 0, - 0, 0, 1, 0, - m->x0, m->y0, 0, 1 + m.xx, m.yx, 0, 0, + m.xy, m.yy, 0, 0, + 0, 0, 1, 0, + m.x0, m.y0, 0, 1 }; CoglMatrix texture_matrix; cogl_matrix_init_from_array (&texture_matrix, texture_matrixfv); @@ -2741,7 +3078,8 @@ get_source_mask_operator_destination_pipelines (cairo_cogl_pipeline_t **pi const cairo_pattern_t *source, cairo_operator_t op, cairo_cogl_surface_t *destination, - cairo_composite_rectangles_t *extents) + cairo_composite_rectangles_t *extents, + cairo_matrix_t *path_transform) { cairo_cogl_template_type template_type; cairo_cogl_device_t *dev = to_device(destination->base.device); @@ -2899,7 +3237,8 @@ get_source_mask_operator_destination_pipelines (cairo_cogl_pipeline_t **pi set_layer_texture_with_attributes (pipelines[1]->pipeline, pipelines[1]->n_layers++, texture, - &attributes); + &attributes, + path_transform); cogl_object_unref (texture); if (pipelines[1]->src_tex_clip.buf.base.num_ops > 0) @@ -2953,7 +3292,8 @@ get_source_mask_operator_destination_pipelines (cairo_cogl_pipeline_t **pi set_layer_texture_with_attributes (pipelines[1]->pipeline, pipelines[1]->n_layers++, texture, - &attributes); + &attributes, + path_transform); } if (pipelines[0]) { if (mask_tex_clip.buf.base.num_ops > 0) { @@ -2965,7 +3305,8 @@ get_source_mask_operator_destination_pipelines (cairo_cogl_pipeline_t **pi set_layer_texture_with_attributes (pipelines[0]->pipeline, pipelines[0]->n_layers++, texture, - &attributes); + &attributes, + path_transform); } _cairo_path_fixed_fini (&mask_tex_clip); @@ -3147,8 +3488,9 @@ _cairo_cogl_surface_paint (void *abstract_surface, source, op, surface, - &extents); - if (!pipelines[0] && !pipelines[1]) { + &extents, + NULL); + if (unlikely (pipelines[0] == NULL && pipelines[1] == NULL)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto BAIL; } @@ -3210,8 +3552,9 @@ _cairo_cogl_surface_mask (void *abstract_surface, source, op, surface, - &extents); - if (!pipelines[0] && !pipelines[1]) { + &extents, + NULL); + if (unlikely (pipelines[0] == NULL && pipelines[1] == NULL)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto BAIL; } @@ -3242,230 +3585,6 @@ BAIL: return status; } -static cairo_bool_t -_cairo_cogl_path_fill_meta_equal (const void *key_a, const void *key_b) -{ - const cairo_cogl_path_fill_meta_t *meta0 = key_a; - const cairo_cogl_path_fill_meta_t *meta1 = key_b; - - return _cairo_path_fixed_equal (meta0->user_path, meta1->user_path); -} - -static cairo_bool_t -_cairo_cogl_stroke_style_equal (const cairo_stroke_style_t *a, - const cairo_stroke_style_t *b) -{ - if (a->line_width == b->line_width && - a->line_cap == b->line_cap && - a->line_join == b->line_join && - a->miter_limit == b->miter_limit && - a->num_dashes == b->num_dashes && - a->dash_offset == b->dash_offset) - { - unsigned int i; - for (i = 0; i < a->num_dashes; i++) { - if (a->dash[i] != b->dash[i]) - return FALSE; - } - } - return TRUE; -} - -static cairo_bool_t -_cairo_cogl_path_stroke_meta_equal (const void *key_a, - const void *key_b) -{ - const cairo_cogl_path_stroke_meta_t *meta0 = key_a; - const cairo_cogl_path_stroke_meta_t *meta1 = key_b; - - return _cairo_cogl_stroke_style_equal (&meta0->style, &meta1->style) && - _cairo_path_fixed_equal (meta0->user_path, meta1->user_path); -} - -static cairo_cogl_path_stroke_meta_t * -_cairo_cogl_path_stroke_meta_reference (cairo_cogl_path_stroke_meta_t *meta) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count)); - - _cairo_reference_count_inc (&meta->ref_count); - - return meta; -} - -static void -_cairo_cogl_path_stroke_meta_destroy (cairo_cogl_path_stroke_meta_t *meta) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count)); - - if (! _cairo_reference_count_dec_and_test (&meta->ref_count)) - return; - - _cairo_path_fixed_fini (meta->user_path); - free (meta->user_path); - - _cairo_stroke_style_fini (&meta->style); - - if (meta->prim) - cogl_object_unref (meta->prim); - - free (meta); -} - -static cairo_cogl_path_stroke_meta_t * -_cairo_cogl_path_stroke_meta_lookup (cairo_cogl_device_t *ctx, - unsigned long hash, - cairo_path_fixed_t *user_path, - const cairo_stroke_style_t *style, - double tolerance) -{ - cairo_cogl_path_stroke_meta_t *ret; - cairo_cogl_path_stroke_meta_t lookup; - - lookup.cache_entry.hash = hash; - lookup.user_path = user_path; - lookup.style = *style; - lookup.tolerance = tolerance; - - ret = _cairo_cache_lookup (&ctx->path_stroke_staging_cache, &lookup.cache_entry); - if (!ret) - ret = _cairo_cache_lookup (&ctx->path_stroke_prim_cache, &lookup.cache_entry); - return ret; -} - -static void -_cairo_cogl_path_stroke_meta_set_prim_size (cairo_cogl_surface_t *surface, - cairo_cogl_path_stroke_meta_t *meta, - size_t size) -{ - /* now that we know the meta structure is associated with a primitive - * we promote it from the staging cache into the primitive cache. - */ - - /* XXX: _cairo_cache borks if you try and remove an entry that's already - * been evicted so we explicitly look it up first... */ - if (_cairo_cache_lookup (&to_device(surface->base.device)->path_stroke_staging_cache, &meta->cache_entry)) { - _cairo_cogl_path_stroke_meta_reference (meta); - _cairo_cache_remove (&to_device(surface->base.device)->path_stroke_staging_cache, &meta->cache_entry); - } - - meta->cache_entry.size = size; - if (_cairo_cache_insert (&to_device(surface->base.device)->path_stroke_prim_cache, &meta->cache_entry) != - CAIRO_STATUS_SUCCESS) - _cairo_cogl_path_stroke_meta_destroy (meta); -} - -static unsigned int -_cairo_cogl_stroke_style_hash (unsigned int hash, - const cairo_stroke_style_t *style) -{ - unsigned int i; - hash = _cairo_hash_bytes (hash, &style->line_width, sizeof (style->line_width)); - hash = _cairo_hash_bytes (hash, &style->line_cap, sizeof (style->line_cap)); - hash = _cairo_hash_bytes (hash, &style->line_join, sizeof (style->line_join)); - hash = _cairo_hash_bytes (hash, &style->miter_limit, sizeof (style->miter_limit)); - hash = _cairo_hash_bytes (hash, &style->num_dashes, sizeof (style->num_dashes)); - hash = _cairo_hash_bytes (hash, &style->dash_offset, sizeof (style->dash_offset)); - for (i = 0; i < style->num_dashes; i++) - hash = _cairo_hash_bytes (hash, &style->dash[i], sizeof (double)); - return hash; -} - -static cairo_cogl_path_stroke_meta_t * -_cairo_cogl_get_path_stroke_meta (cairo_cogl_surface_t *surface, - const cairo_stroke_style_t *style, - double tolerance) -{ - unsigned long hash; - cairo_cogl_path_stroke_meta_t *meta = NULL; - cairo_path_fixed_t *meta_path = NULL; - cairo_status_t status; - - if (!surface->user_path) - return NULL; - - hash = _cairo_path_fixed_hash (surface->user_path); - hash = _cairo_cogl_stroke_style_hash (hash, style); - hash = _cairo_hash_bytes (hash, &tolerance, sizeof (tolerance)); - - meta = _cairo_cogl_path_stroke_meta_lookup (to_device(surface->base.device), hash, - surface->user_path, style, tolerance); - if (meta) - return meta; - - meta = calloc (1, sizeof (cairo_cogl_path_stroke_meta_t)); - if (unlikely (!meta)) - goto BAIL; - CAIRO_REFERENCE_COUNT_INIT (&meta->ref_count, 1); - meta->cache_entry.hash = hash; - meta->counter = 0; - meta_path = _cairo_malloc (sizeof (cairo_path_fixed_t)); - if (unlikely (!meta_path)) - goto BAIL; - /* FIXME: we should add a ref-counted wrapper for our user_paths - * so we don't have to keep copying them here! */ - status = _cairo_path_fixed_init_copy (meta_path, surface->user_path); - if (unlikely (status)) - goto BAIL; - meta->user_path = meta_path; - meta->ctm_inverse = surface->ctm_inverse; - - status = _cairo_stroke_style_init_copy (&meta->style, style); - if (unlikely (status)) { - _cairo_path_fixed_fini (meta_path); - goto BAIL; - } - meta->tolerance = tolerance; - - return meta; - -BAIL: - free (meta_path); - free (meta); - return NULL; -} - -static cairo_int_status_t -_cairo_cogl_stroke_to_primitive (cairo_cogl_surface_t *surface, - 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_bool_t one_shot, - CoglPrimitive **primitive, - size_t *size) -{ - cairo_traps_t traps; - cairo_int_status_t status; - - _cairo_traps_init (&traps); - - status = _cairo_path_fixed_stroke_polygon_to_traps (path, style, - ctm, ctm_inverse, - tolerance, - &traps); - if (unlikely (status)) - goto BAIL; - - if (traps.num_traps == 0) { - status = CAIRO_INT_STATUS_NOTHING_TO_DO; - goto BAIL; - } - - *size = traps.num_traps * sizeof (CoglVertexP2) * 6; - - //g_print ("new stroke prim\n"); - *primitive = _cairo_cogl_traps_to_composite_prim (surface, &traps, one_shot); - if (unlikely (!*primitive)) { - status = CAIRO_INT_STATUS_NO_MEMORY; - goto BAIL; - } - -BAIL: - _cairo_traps_fini (&traps); - return status; -} - static cairo_int_status_t _cairo_cogl_surface_stroke (void *abstract_surface, cairo_operator_t op, @@ -3482,14 +3601,8 @@ _cairo_cogl_surface_stroke (void *abstract_surface, cairo_composite_rectangles_t extents; cairo_cogl_pipeline_t *pipelines[2]; cairo_int_status_t status; -#ifdef ENABLE_PATH_CACHE - cairo_cogl_path_stroke_meta_t *meta = NULL; - cairo_matrix_t transform_matrix; -#endif - cairo_matrix_t *transform = NULL; - cairo_bool_t one_shot = TRUE; + cairo_matrix_t transform; CoglPrimitive *prim = NULL; - cairo_bool_t new_prim = FALSE; if (! is_operator_supported (op)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -3503,44 +3616,15 @@ _cairo_cogl_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; -#ifdef ENABLE_PATH_CACHE - /* FIXME: we are currently leaking the meta state if we don't reach - * the cache_insert at the end. */ - meta = _cairo_cogl_get_path_stroke_meta (surface, style, tolerance); - if (meta) { - prim = meta->prim; - if (prim) { - cairo_matrix_multiply (&transform_matrix, - &meta->ctm_inverse, - &surface->ctm); - transform = &transform_matrix; - } else if (meta->counter++ > 10) { - one_shot = FALSE; - } - } -#endif - - if (!prim) { - size_t prim_size; - status = _cairo_cogl_stroke_to_primitive (surface, path, style, - ctm, ctm_inverse, tolerance, - one_shot, &prim, - &prim_size); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO - && _cairo_operator_bounded_by_mask (op) == FALSE) { - /* Just render the unbounded rectangle */ - prim = NULL; - } else if (unlikely (status)) { - goto BAIL; - } else { - new_prim = TRUE; - } -#if defined (ENABLE_PATH_CACHE) - if (meta && prim) { - meta->prim = cogl_object_ref (prim); - _cairo_cogl_path_stroke_meta_set_prim_size (surface, meta, prim_size); - } -#endif + status = _cairo_cogl_stroke_to_primitive (surface, path, style, + tolerance, TRUE, &prim, + &transform); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO + && _cairo_operator_bounded_by_mask (op) == FALSE) { + /* Just render the unbounded rectangle */ + prim = NULL; + } else if (unlikely (status)) { + goto BAIL; } get_source_mask_operator_destination_pipelines (pipelines, @@ -3548,8 +3632,9 @@ _cairo_cogl_surface_stroke (void *abstract_surface, source, op, surface, - &extents); - if (!pipelines[0] && !pipelines[1]) { + &extents, + &transform); + if (unlikely (pipelines[0] == NULL && pipelines[1] == NULL)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto BAIL; } @@ -3560,16 +3645,16 @@ _cairo_cogl_surface_stroke (void *abstract_surface, _cairo_cogl_journal_log_primitive (surface, pipelines[0], prim, - transform); + &transform); if (pipelines[1]) _cairo_cogl_journal_log_primitive (surface, pipelines[1], prim, - transform); + &transform); BAIL: /* The journal will take a reference on the primitive... */ - if (new_prim) + if (prim) cogl_object_unref (prim); _cairo_composite_rectangles_fini (&extents); @@ -3577,123 +3662,6 @@ BAIL: return status; } -static cairo_cogl_path_fill_meta_t * -_cairo_cogl_path_fill_meta_reference (cairo_cogl_path_fill_meta_t *meta) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count)); - - _cairo_reference_count_inc (&meta->ref_count); - - return meta; -} - -static void -_cairo_cogl_path_fill_meta_destroy (cairo_cogl_path_fill_meta_t *meta) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count)); - - if (! _cairo_reference_count_dec_and_test (&meta->ref_count)) - return; - - _cairo_path_fixed_fini (meta->user_path); - free (meta->user_path); - - if (meta->prim) - cogl_object_unref (meta->prim); - - free (meta); -} - -static cairo_cogl_path_fill_meta_t * -_cairo_cogl_path_fill_meta_lookup (cairo_cogl_device_t *ctx, - unsigned long hash, - cairo_path_fixed_t *user_path) -{ - cairo_cogl_path_fill_meta_t *ret; - cairo_cogl_path_fill_meta_t lookup; - - lookup.cache_entry.hash = hash; - lookup.user_path = user_path; - - ret = _cairo_cache_lookup (&ctx->path_fill_staging_cache, &lookup.cache_entry); - if (!ret) - ret = _cairo_cache_lookup (&ctx->path_fill_prim_cache, &lookup.cache_entry); - return ret; -} - -static void -_cairo_cogl_path_fill_meta_set_prim_size (cairo_cogl_surface_t *surface, - cairo_cogl_path_fill_meta_t *meta, - size_t size) -{ - /* now that we know the meta structure is associated with a primitive - * we promote it from the staging cache into the primitive cache. - */ - - /* XXX: _cairo_cache borks if you try and remove an entry that's already - * been evicted so we explicitly look it up first... */ - if (_cairo_cache_lookup (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry)) { - _cairo_cogl_path_fill_meta_reference (meta); - _cairo_cache_remove (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry); - } - - meta->cache_entry.size = size; - if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_prim_cache, &meta->cache_entry) != - CAIRO_STATUS_SUCCESS) - _cairo_cogl_path_fill_meta_destroy (meta); -} - -static cairo_cogl_path_fill_meta_t * -_cairo_cogl_get_path_fill_meta (cairo_cogl_surface_t *surface) -{ - unsigned long hash; - cairo_cogl_path_fill_meta_t *meta = NULL; - cairo_path_fixed_t *meta_path = NULL; - cairo_status_t status; - - if (!surface->user_path) - return NULL; - - hash = _cairo_path_fixed_hash (surface->user_path); - - meta = _cairo_cogl_path_fill_meta_lookup (to_device(surface->base.device), - hash, surface->user_path); - if (meta) - return meta; - - meta = calloc (1, sizeof (cairo_cogl_path_fill_meta_t)); - if (unlikely (!meta)) - goto BAIL; - meta->cache_entry.hash = hash; - meta->counter = 0; - CAIRO_REFERENCE_COUNT_INIT (&meta->ref_count, 1); - meta_path = _cairo_malloc (sizeof (cairo_path_fixed_t)); - if (unlikely (!meta_path)) - goto BAIL; - /* FIXME: we should add a ref-counted wrapper for our user_paths - * so we don't have to keep copying them here! */ - status = _cairo_path_fixed_init_copy (meta_path, surface->user_path); - if (unlikely (status)) - goto BAIL; - meta->user_path = meta_path; - meta->ctm_inverse = surface->ctm_inverse; - - /* To start with - until we associate a CoglPrimitive with the meta - * structure - we keep the meta in a staging structure until we - * see whether it actually gets re-used. */ - meta->cache_entry.size = 1; - if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry) != - CAIRO_STATUS_SUCCESS) - _cairo_cogl_path_fill_meta_destroy (meta); - - return meta; - -BAIL: - free (meta_path); - free (meta); - return NULL; -} - static cairo_int_status_t _cairo_cogl_surface_fill (void *abstract_surface, cairo_operator_t op, @@ -3707,14 +3675,8 @@ _cairo_cogl_surface_fill (void *abstract_surface, cairo_cogl_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; cairo_int_status_t status; -#ifdef ENABLE_PATH_CACHE - cairo_cogl_path_fill_meta_t *meta = NULL; - cairo_matrix_t transform_matrix; -#endif - cairo_matrix_t *transform = NULL; - cairo_bool_t one_shot = TRUE; + cairo_matrix_t transform; CoglPrimitive *prim = NULL; - cairo_bool_t new_prim = FALSE; cairo_cogl_pipeline_t *pipelines[2]; if (! is_operator_supported (op)) @@ -3728,42 +3690,16 @@ _cairo_cogl_surface_fill (void *abstract_surface, return status; #ifndef FILL_WITH_COGL_PATH -#ifdef ENABLE_PATH_CACHE - meta = _cairo_cogl_get_path_fill_meta (surface); - if (meta) { - prim = meta->prim; - if (prim) { - cairo_matrix_multiply (&transform_matrix, - &meta->ctm_inverse, - &surface->ctm); - transform = &transform_matrix; - } else if (meta->counter++ > 10) { - one_shot = FALSE; - } - } -#endif /* ENABLE_PATH_CACHE */ - - if (!prim) { - size_t prim_size; - status = _cairo_cogl_fill_to_primitive (surface, path, fill_rule, tolerance, - one_shot, &prim, &prim_size); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO - && _cairo_operator_bounded_by_mask (op) == FALSE) { - /* Just render the unbounded rectangle */ - prim = NULL; - } else if (unlikely (status)) { - goto BAIL; - } else { - new_prim = TRUE; - } -#ifdef ENABLE_PATH_CACHE - if (meta && prim) { - meta->prim = cogl_object_ref (prim); - _cairo_cogl_path_fill_meta_set_prim_size (surface, meta, prim_size); - } -#endif /* ENABLE_PATH_CACHE */ + status = _cairo_cogl_fill_to_primitive (surface, path, fill_rule, + tolerance, TRUE, &prim, + &transform); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO + && _cairo_operator_bounded_by_mask (op) == FALSE) { + /* Just render the unbounded rectangle */ + prim = NULL; + } else if (unlikely (status)) { + goto BAIL; } - #endif /* !FILL_WITH_COGL_PATH */ get_source_mask_operator_destination_pipelines (pipelines, @@ -3771,8 +3707,9 @@ _cairo_cogl_surface_fill (void *abstract_surface, source, op, surface, - &extents); - if (!pipelines[0] && !pipelines[1]) { + &extents, + &transform); + if (unlikely (pipelines[0] == NULL && pipelines[1] == NULL)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto BAIL; } @@ -3784,12 +3721,12 @@ _cairo_cogl_surface_fill (void *abstract_surface, _cairo_cogl_journal_log_primitive (surface, pipelines[0], prim, - transform); + &transform); if (pipelines[1]) _cairo_cogl_journal_log_primitive (surface, pipelines[1], prim, - transform); + &transform); #else CoglPath * cogl_path = _cairo_cogl_util_path_from_cairo (path, fill_rule, tolerance); @@ -3806,88 +3743,14 @@ _cairo_cogl_surface_fill (void *abstract_surface, #endif BAIL: -#ifndef FILL_WITH_COGL_PATH /* The journal will take a reference on the prim */ - if (new_prim) + if (prim) cogl_object_unref (prim); -#endif - _cairo_composite_rectangles_fini (&extents); return status; } -cairo_int_status_t -_cairo_cogl_surface_fill_rectangle (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - double x, - double y, - double width, - double height, - cairo_matrix_t *ctm, - const cairo_clip_t *clip) -{ - cairo_cogl_surface_t *surface = abstract_surface; - cairo_composite_rectangles_t extents; - cairo_int_status_t status; - cairo_cogl_pipeline_t *pipelines[2]; - - if (! is_operator_supported (op)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - if (source->type == CAIRO_PATTERN_TYPE_SOLID) { - /* These extents will be larger than necessary, but in the absence - * of a specialized function, they will do */ - status = - _cairo_composite_rectangles_init_for_paint (&extents, - &surface->base, - op, - source, - clip); - if (unlikely (status)) - return status; - - get_source_mask_operator_destination_pipelines (pipelines, - NULL, - source, - op, - surface, - &extents); - if (!pipelines[0] && !pipelines[1]) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } - - _cairo_cogl_log_clip (surface, clip); - - if (pipelines[0]) - _cairo_cogl_journal_log_rectangle (surface, - pipelines[0], - x, y, width, height, - ctm); - if (pipelines[1]) - _cairo_cogl_journal_log_rectangle (surface, - pipelines[1], - x, y, width, height, - ctm); - -BAIL: - _cairo_composite_rectangles_fini (&extents); - - return status; - } else { - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - /* TODO: - * We need to acquire the textures here, look at the corresponding - * attributes and see if this can be trivially handled by logging - * a textured rectangle only needing simple scaling or translation - * of texture coordinates. - */ -} - /* Mostly taken from cairo_vg_surface.c */ /* TODO: implement actual font support, with either cogl-pango's glyph * cache or our own */ @@ -3900,7 +3763,6 @@ _cairo_cogl_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { - cairo_cogl_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_path_fixed_t path; int num_chunk_glyphs; @@ -3925,15 +3787,6 @@ _cairo_cogl_surface_show_glyphs (void *abstract_surface, if (unlikely (status)) goto BAIL; -#ifdef NEED_COGL_CONTEXT - /* XXX: in cairo-cogl-context.c we set some sideband data on the - * surface before issuing a fill so we need to do that here too... */ - surface->user_path = &path; - cairo_matrix_init_identity (&surface->ctm); - surface->ctm_inverse = surface->ctm; - surface->path_is_rectangle = FALSE; -#endif - status = _cairo_cogl_surface_fill (abstract_surface, op, source, &path, CAIRO_FILL_RULE_WINDING, @@ -3957,11 +3810,7 @@ BAIL: const cairo_surface_backend_t _cairo_cogl_surface_backend = { CAIRO_SURFACE_TYPE_COGL, _cairo_cogl_surface_finish, -#ifdef NEED_COGL_CONTEXT - _cairo_cogl_context_create, -#else _cairo_default_context_create, -#endif _cairo_cogl_surface_create_similar, NULL, /* create similar image */ @@ -4232,11 +4081,12 @@ _cairo_cogl_device_finish (void *device) /* XXX: Drop references to external resources */ _cairo_cache_fini (&dev->linear_cache); - _cairo_cache_fini (&dev->path_fill_staging_cache); _cairo_cache_fini (&dev->path_fill_prim_cache); - _cairo_cache_fini (&dev->path_stroke_staging_cache); _cairo_cache_fini (&dev->path_stroke_prim_cache); + _cairo_freelist_fini (&dev->path_fill_meta_freelist); + _cairo_freelist_fini (&dev->path_stroke_meta_freelist); + if (dev->buffer_stack && dev->buffer_stack_offset) { cogl_buffer_unmap (dev->buffer_stack); cogl_object_unref (dev->buffer_stack); @@ -4308,18 +4158,6 @@ cairo_cogl_device_create (CoglContext *cogl_context) return _cairo_device_create_in_error (status); } - status = _cairo_cache_init (&dev->path_fill_staging_cache, - _cairo_cogl_path_fill_meta_equal, - NULL, - (cairo_destroy_func_t) _cairo_cogl_path_fill_meta_destroy, - 1000); - - status = _cairo_cache_init (&dev->path_stroke_staging_cache, - _cairo_cogl_path_stroke_meta_equal, - NULL, - (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy, - 1000); - status = _cairo_cache_init (&dev->path_fill_prim_cache, _cairo_cogl_path_fill_meta_equal, NULL, @@ -4332,6 +4170,11 @@ cairo_cogl_device_create (CoglContext *cogl_context) (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy, CAIRO_COGL_PATH_META_CACHE_SIZE); + _cairo_freelist_init (&dev->path_fill_meta_freelist, + sizeof(cairo_cogl_path_fill_meta_t)); + _cairo_freelist_init (&dev->path_stroke_meta_freelist, + sizeof(cairo_cogl_path_stroke_meta_t)); + _cairo_device_init (&dev->base, &_cairo_cogl_device_backend); return &dev->base; } diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 760f092e3..6acdea9dd 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -94,10 +94,6 @@ cairo_debug_reset_static_data (void) _cairo_default_context_reset_static_data (); -#if CAIRO_HAS_COGL_SURFACE - _cairo_cogl_context_reset_static_data (); -#endif - CAIRO_MUTEX_FINALIZE (); } diff --git a/src/meson.build b/src/meson.build index 5a3fb92e5..160e6657c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -217,7 +217,6 @@ cairo_feature_sources = { 'cairo-cogl': [ 'cairo-cogl-surface.c', 'cairo-cogl-gradient.c', - 'cairo-cogl-context.c', 'cairo-cogl-utils.c', ], 'cairo-directfb': [ |