[cairo] [PATCH 34/39] [OpenVG] reuse paint object, have a cache of images

tardyp at gmail.com tardyp at gmail.com
Fri Jul 10 10:02:36 PDT 2009


From: Øyvind Kolås <pippin at gimp.org>

Patch based on initial hack for reusing cairo_image_t's
-------

Hi!

Attached is the patch from the current repository HEAD to caching
persistent images plus the paint reusability optimization. With the
latest ShivaVG source it should restore the previous performace while
still supporting additional formats. Here's a brief comment of
changes:

* cairo_openvg_setup_solid_source: PAINT_TYPE is re-set to PAINT_TYPE_COLOR

* cairo_openvg_setup_surface_source: doesn't rearrange the data in a
temp buffer but passes it to openvg directly using ARGB format. I'm
not sure if thats supported by AmanithVG, so I just commented it out.
It does work with ShivaVG perfectly, though.

* setup_source: removed the check for non-destructed paint

* teardown_source: removed paint destruction code

* added _cairo_openvg_surface_finish to destroy the reusable paint object

* cairo_openvg_surface_create: creates the reusable paint object

cheers,
Ivan
---
 src/cairo-openvg-surface.c |   95 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/src/cairo-openvg-surface.c b/src/cairo-openvg-surface.c
index 2782646..bed9902 100644
--- a/src/cairo-openvg-surface.c
+++ b/src/cairo-openvg-surface.c
@@ -39,6 +39,14 @@
 
 #define MAX_OPACITIES 32
 
+typedef struct cached_image_t {
+    VGImage  vg_image;        /*< set to 0 when entry not used */
+    void    *cairo_image;
+    void    *data;
+} cached_image_t;
+
+#define MAX_IMAGES 32
+
 typedef struct cairo_openvg_surface {
     cairo_surface_t base;
     cairo_content_t content;
@@ -51,6 +59,8 @@ typedef struct cairo_openvg_surface {
     double          alpha;
     double          opacity[MAX_OPACITIES];
     int             opacity_level;
+
+    cached_image_t  images[MAX_IMAGES];
 } cairo_openvg_surface_t;
 
 static void
@@ -477,6 +487,8 @@ _cairo_openvg_setup_solid_source (cairo_openvg_surface_t *vgsurface,
                      spat->color.green,
                      spat->color.blue,
                      spat->color.alpha * vgsurface->alpha};
+  
+  vgSetParameteri(vgsurface->source_paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
   vgSetParameterfv (vgsurface->source_paint, VG_PAINT_COLOR, 4, color);
   return CAIRO_STATUS_SUCCESS;
 }
@@ -505,19 +517,60 @@ _cairo_openvg_setup_surface_source (cairo_openvg_surface_t  *vgsurface,
           image->format == CAIRO_FORMAT_A8 ||
           image->format == CAIRO_FORMAT_A1);
 
+  
+  {
+    int i;
+    for (i=0; i<MAX_IMAGES;i++)
+      {
+        if (vgsurface->images[i].vg_image &&
+            (vgsurface->images[i].cairo_image == image || 
+             vgsurface->images[i].data == image->data))
+          {
+            vgsurface->source_image = vgsurface->images[i].vg_image;
+            /*fprintf (stderr, "found in cache!\n");*/
+            goto USED_CACHE;
+          }
+      }
+  }
+
   vgsurface->source_image = vgCreateImage (VG_sRGBA_8888, 
     image->width, image->height, VG_IMAGE_QUALITY_FASTER);
   /* NONALIASED, FASTER, BETTER */
 
-  /*printf ("image: %ix%i\n", image->width, image->height);*/
 
-  data = malloc (image->width * image->height * 4);
+  { /* store in cache */
+    int i;
+    int done = 0;
+    for (i=0; i<MAX_IMAGES;i++)
+      {
+        if (vgsurface->images[i].vg_image == 0)
+          {
+            vgsurface->images[i].vg_image = vgsurface->source_image;
+            vgsurface->images[i].cairo_image = image;
+            vgsurface->images[i].data = image->data;
+            done = 1;
+            break;
+          }
+      }
+    if (done == 0)
+      {
+        i=1;
+        vgDestroyImage (vgsurface->images[i].vg_image);
+        vgsurface->images[i].vg_image = vgsurface->source_image;
+        vgsurface->images[i].cairo_image = image;
+        vgsurface->images[i].data = image->data;
+      }
+  }
+
+  printf ("image: %p %p %ix%i\n", image, image->data, image->width, image->height);
+
+  /*data = malloc (image->width * image->height * 4);*/
 
   /* This extra allocation and copy/conversion should not be neccesary if the
    * OpenVG implementation supports the pixelformats in the specification, at
    * the moment it doesn't seem like neither ShivaVG nor AmantihVG does so
    * however.
-   */
+   */ /*
   {
     int i;
     for (i=0; i<image->width * image->height; i++)
@@ -527,12 +580,14 @@ _cairo_openvg_setup_surface_source (cairo_openvg_surface_t  *vgsurface,
         data[4*i+2] = image->data[4*i+0];
         data[4*i+3] = image->data[4*i+3];
       }
-  }
+  } */
+
+  vgImageSubData (vgsurface->source_image, image->data, image->width*4,
+     VG_sARGB_8888, 0, 0, image->width, image->height);
 
-  vgImageSubData (vgsurface->source_image, data, image->width*4,
-     VG_sRGBA_8888, 0, 0, image->width, image->height);
+  /*free (data);*/
 
-  free (data);
+USED_CACHE:
 
   vgSetParameteri (vgsurface->source_paint,
                    VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
@@ -580,11 +635,9 @@ setup_source (cairo_openvg_surface_t *vgsurface,
   /* this will bomb if one of the prior paint ops have failed to
    * clean up after itself
    */
-
-  assert (vgsurface->source_paint == 0);
+  
   assert (vgsurface->source_image == 0);
-
-  vgsurface->source_paint = vgCreatePaint();
+  
   if (source->type == CAIRO_PATTERN_TYPE_SOLID)
     {
       cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
@@ -616,14 +669,9 @@ static cairo_status_t
 teardown_source (cairo_openvg_surface_t *vgsurface,
                  cairo_pattern_t        *source)
 {
-  if (vgsurface->source_paint)
-    {
-      vgDestroyPaint (vgsurface->source_paint);
-      vgsurface->source_paint = 0;
-    }
   if (vgsurface->source_image)
     {
-      vgDestroyImage (vgsurface->source_image);
+      /*vgDestroyImage (vgsurface->source_image);*/
       vgsurface->source_image = 0;
     }
   return CAIRO_STATUS_SUCCESS;
@@ -714,7 +762,7 @@ _cairo_openvg_surface_fill (void               *asurface,
   rv = setup_source (vgsurface, source);
   if (rv)
     goto BAIL;
-
+  
   vgSetPaint(vgsurface->source_paint, VG_FILL_PATH);
   vgDrawPath (vg_path.path, VG_FILL_PATH);
   vgDestroyPath (vg_path.path);
@@ -881,11 +929,19 @@ _cairo_openvg_surface_show_glyphs (void                *asurface,
   return status;
 }
 
+static cairo_status_t
+_cairo_openvg_surface_finish (void *abstract_surface)
+{
+  cairo_openvg_surface_t *vgsurface = (cairo_openvg_surface_t*) abstract_surface;
+  if (vgsurface->source_paint != VG_INVALID_HANDLE)
+    vgDestroyPaint (vgsurface->source_paint);
+}
+
 static const struct _cairo_surface_backend
 cairo_openvg_surface_backend = {
     CAIRO_SURFACE_TYPE_OPENVG,
     _cairo_openvg_surface_create_similar,
-    NULL, /* finish */
+    _cairo_openvg_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
@@ -929,6 +985,7 @@ cairo_openvg_surface_create (int width, int height)
     s->alpha = 1.0;
     s->opacity_level = 0;
     s->opacity[s->opacity_level] = 1.0;
+    s->source_paint = vgCreatePaint();
 
     vgLoadIdentity();
     /* The default transform of cairo and OpenVG differ, (cairo has the
-- 
1.6.0.4



More information about the cairo mailing list