summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Matsumura <gmmatsumura01@bvsd.org>2020-08-05 23:10:42 -0600
committerGeorge Matsumura <gmmatsumura01@bvsd.org>2020-08-25 02:30:58 -0600
commitecbd7ed1740485ccb2be29326ffa6e5ace1df2a7 (patch)
tree5c2bd8ca4d74d0ff8c86833753b288fd90801fa1
parent939da43c44ec28b278db36ab744a1176bbdfa890 (diff)
downloadcairo-ecbd7ed1740485ccb2be29326ffa6e5ace1df2a7.tar.gz
cogl: Add new path cache
This redesigns the path cache so that it does not mess with the context functions, thereby hopefully making it much more resilient to changes in the rest of cairo that change the way the default context works. It is also much simpler, and it is anticipated that it will be more maintainable. Performance in contrast to the old cache design speeds up most traces in cairo-perf-trace, and slows down only a lesser few by <20%. Signed-off-by: George Matsumura <gmmatsumura01@bvsd.org>
-rw-r--r--boilerplate/cairo-boilerplate-cogl.c12
-rw-r--r--src/Makefile.sources2
-rw-r--r--src/cairo-cogl-context-private.h58
-rw-r--r--src/cairo-cogl-context.c1063
-rw-r--r--src/cairo-cogl-private.h17
-rw-r--r--src/cairo-cogl-surface.c1133
-rw-r--r--src/cairo-debug.c4
-rw-r--r--src/meson.build1
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': [