Revert "clutter-cairo-texture: Use the new cogl_pixel_buffer API"
authorNeil Roberts <neil@linux.intel.com>
Mon, 10 May 2010 14:33:05 +0000 (15:33 +0100)
committerNeil Roberts <neil@linux.intel.com>
Mon, 10 May 2010 15:17:32 +0000 (16:17 +0100)
This reverts commit 716ec82db8bec57e35d51e8dee5468435fc9e59e.

The Cogl pixel buffer API currently has problems if an atlas texture
is created or the format needs to be converted. The atlas problem
doesn't currently show because the atlas rejects BGR textures anyway
but we may want to change this soon. The problem with format
conversion would happen under GLES because that does not support BGR
textures at all so Cogl has to do the conversion. However it doesn't
currently show either because GLES has no support for buffer objects
anyway.

It's also questionable whether the patch would give any performance
benefit because Cairo needs read/write access which implies the buffer
can't be put in write-optimised memory.

Conflicts:

clutter/clutter-cairo-texture.c

http://bugzilla.openedhand.com/show_bug.cgi?id=1982

clutter/clutter-cairo-texture.c

index e7ae1df..88cf5d8 100644 (file)
@@ -81,8 +81,6 @@
 #include "clutter-cairo-texture.h"
 #include "clutter-debug.h"
 #include "clutter-private.h"
-#include "cogl/cogl-pixel-buffer.h"
-#include "cogl/cogl-buffer.h"
 
 G_DEFINE_TYPE (ClutterCairoTexture,
                clutter_cairo_texture,
@@ -120,15 +118,14 @@ enum
 
 struct _ClutterCairoTexturePrivate
 {
-  cairo_format_t format;
+  cairo_format_t   format;
 
-  CoglHandle     buffer;
-  guint          buffer_width;
-  guint          buffer_height;
+  cairo_surface_t *cr_surface;
+  guchar          *cr_surface_data;
 
-  guint          width;
-  guint          height;
-  guint          rowstride;
+  guint            width;
+  guint            height;
+  guint            rowstride;
 };
 
 typedef struct
@@ -146,6 +143,15 @@ typedef struct
 } ClutterCairoTextureContext;
 
 static const cairo_user_data_key_t clutter_cairo_texture_surface_key;
+static const cairo_user_data_key_t clutter_cairo_texture_context_key;
+
+static void
+clutter_cairo_texture_surface_destroy (void *data)
+{
+  ClutterCairoTexture *cairo = data;
+
+  cairo->priv->cr_surface = NULL;
+}
 
 static void
 clutter_cairo_texture_set_property (GObject      *object,
@@ -204,10 +210,23 @@ clutter_cairo_texture_finalize (GObject *object)
 {
   ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv;
 
-  if (priv->buffer)
+  if (priv->cr_surface)
     {
-      cogl_handle_unref (priv->buffer);
-      priv->buffer = NULL;
+      cairo_surface_t *surface = priv->cr_surface;
+
+      cairo_surface_finish (priv->cr_surface);
+      cairo_surface_set_user_data (priv->cr_surface,
+                                   &clutter_cairo_texture_surface_key,
+                                   NULL, NULL);
+      cairo_surface_destroy (surface);
+
+      priv->cr_surface = NULL;
+    }
+
+  if (priv->cr_surface_data)
+    {
+      g_free (priv->cr_surface_data);
+      priv->cr_surface_data = NULL;
     }
 
   G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->finalize (object);
@@ -217,30 +236,80 @@ static inline void
 clutter_cairo_texture_surface_resize_internal (ClutterCairoTexture *cairo)
 {
   ClutterCairoTexturePrivate *priv = cairo->priv;
+  CoglHandle cogl_texture;
 
-  if (priv->buffer)
+  if (priv->cr_surface)
     {
-      /* If the buffer is already the right size then don't bother
+      cairo_surface_t *surface = priv->cr_surface;
+
+      /* If the surface is already the right size then don't bother
          doing anything */
-      if (priv->buffer_width == priv->width &&
-          priv->buffer_height == priv->height)
+      if (priv->width == cairo_image_surface_get_width (priv->cr_surface)
+          && priv->height == cairo_image_surface_get_height (priv->cr_surface))
         return;
 
-      cogl_handle_unref (priv->buffer);
-      priv->buffer = COGL_INVALID_HANDLE;
+      cairo_surface_finish (surface);
+      cairo_surface_set_user_data (surface,
+                                   &clutter_cairo_texture_surface_key,
+                                  NULL, NULL);
+      cairo_surface_destroy (surface);
+
+      priv->cr_surface = NULL;
+    }
+
+  if (priv->cr_surface_data)
+    {
+      g_free (priv->cr_surface_data);
+      priv->cr_surface_data = NULL;
     }
 
   if (priv->width == 0 || priv->height == 0)
     return;
 
-  priv->buffer =
-    cogl_pixel_buffer_new_for_size (priv->width,
-                                    priv->height,
-                                    CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
-                                    &priv->rowstride);
+#if CAIRO_VERSION > 106000
+  priv->rowstride = cairo_format_stride_for_width (priv->format, priv->width);
+#else
+  /* poor man's version of cairo_format_stride_for_width() */
+  switch (priv->format)
+    {
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+      priv->rowstride = priv->width * 4;
+      break;
+
+    case CAIRO_FORMAT_A8:
+    case CAIRO_FORMAT_A1:
+      priv->rowstride = priv->width;
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+#endif /* CAIRO_VERSION > 106000 */
+
+  priv->cr_surface_data = g_malloc0 (priv->height * priv->rowstride);
+  priv->cr_surface =
+    cairo_image_surface_create_for_data (priv->cr_surface_data,
+                                         priv->format,
+                                         priv->width, priv->height,
+                                         priv->rowstride);
 
-  priv->buffer_width = priv->width;
-  priv->buffer_height = priv->height;
+  cairo_surface_set_user_data (priv->cr_surface,
+                               &clutter_cairo_texture_surface_key,
+                              cairo,
+                               clutter_cairo_texture_surface_destroy);
+
+  /* Create a blank Cogl texture
+   */
+  cogl_texture = cogl_texture_new_from_data (priv->width, priv->height,
+                                             COGL_TEXTURE_NONE,
+                                             CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
+                                             COGL_PIXEL_FORMAT_ANY,
+                                             priv->rowstride,
+                                             priv->cr_surface_data);
+  clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (cairo), cogl_texture);
+  cogl_handle_unref (cogl_texture);
 }
 
 static void
@@ -252,8 +321,8 @@ clutter_cairo_texture_notify (GObject    *object,
      that if both the width and height properties are set using a
      single call to g_object_set then the surface will only be resized
      once because the notifications will be frozen in between */
-  if (!strcmp ("surface-width", pspec->name) ||
-      !strcmp ("surface-height", pspec->name))
+  if (!strcmp ("surface-width", pspec->name)
+      || !strcmp ("surface-height", pspec->name))
     {
       ClutterCairoTexture *cairo = CLUTTER_CAIRO_TEXTURE (object);
 
@@ -384,31 +453,46 @@ clutter_cairo_texture_new (guint width,
 }
 
 static void
-clutter_cairo_texture_surface_destroy (void *data)
+clutter_cairo_texture_context_destroy (void *data)
 {
   ClutterCairoTextureContext *ctxt = data;
   ClutterCairoTexture *cairo = ctxt->cairo;
   ClutterCairoTexturePrivate *priv = cairo->priv;
+  guchar *cairo_data;
+  gint cairo_width, cairo_height;
+  gint surface_width, surface_height;
   CoglHandle cogl_texture;
 
-  if (!priv->buffer)
+  if (!priv->cr_surface)
     return;
 
-  cogl_buffer_unmap (priv->buffer);
+  surface_width  = cairo_image_surface_get_width (priv->cr_surface);
+  surface_height = cairo_image_surface_get_height (priv->cr_surface);
 
-  cogl_texture =
-    cogl_texture_new_from_buffer (priv->buffer,
-                                  priv->buffer_width,
-                                  priv->buffer_height,
-                                  COGL_TEXTURE_NONE,
-                                  CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
-                                  COGL_PIXEL_FORMAT_ANY,
-                                  priv->rowstride,
-                                  0);
+  cairo_width  = MIN (ctxt->rect.width, surface_width);
+  cairo_height = MIN (ctxt->rect.height, surface_height);
 
-  clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (cairo), cogl_texture);
+  cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (cairo));
 
-  cogl_handle_unref (cogl_texture);
+  if (!cairo_width || !cairo_height || cogl_texture == COGL_INVALID_HANDLE)
+    {
+      g_free (ctxt);
+
+      return;
+    }
+
+  cairo_data = (priv->cr_surface_data
+             + (ctxt->rect.y * priv->rowstride)
+             + (ctxt->rect.x * 4));
+
+  cogl_texture_set_region (cogl_texture,
+                           0, 0,
+                           ctxt->rect.x, ctxt->rect.y,
+                           cairo_width, cairo_height,
+                           cairo_width, cairo_height,
+                           CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
+                           priv->rowstride,
+                           cairo_data);
 
   g_free (ctxt);
 
@@ -475,8 +559,6 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
   ClutterCairoTextureContext *ctxt;
   ClutterCairoTextureRectangle region, area, inter;
   cairo_t *cr;
-  cairo_surface_t *surface;
-  CoglHandle material;
 
   g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), NULL);
 
@@ -499,7 +581,7 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
       return NULL;
     }
 
-  if (!priv->buffer)
+  if (!priv->cr_surface)
     return NULL;
 
   ctxt = g_new0 (ClutterCairoTextureContext, 1);
@@ -523,30 +605,9 @@ clutter_cairo_texture_create_region (ClutterCairoTexture *self,
   ctxt->rect.width = inter.width;
   ctxt->rect.height = inter.height;
 
-  /* Destroy the existing texture so that the GL driver won't have to
-     copy it when we map the PBO */
-  if ((material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (self))))
-    cogl_material_set_layer (material, 0, COGL_INVALID_HANDLE);
-
-  /* Create a surface to render directly to the PBO */
-  surface =
-    cairo_image_surface_create_for_data (cogl_buffer_map (priv->buffer,
-                                                          COGL_BUFFER_ACCESS_READ |
-                                                          COGL_BUFFER_ACCESS_WRITE),
-                                         priv->format,
-                                         priv->buffer_width,
-                                         priv->buffer_height,
-                                         priv->rowstride);
-
-  /* Set a key so that we can recreate the texture when the surface is
-     destroyed */
-  cairo_surface_set_user_data (surface, &clutter_cairo_texture_surface_key,
-                               ctxt, clutter_cairo_texture_surface_destroy);
-
-  cr = cairo_create (surface);
-  /* Remove the reference we have on the surface so that it will be
-     destroyed when the context is destroyed */
-  cairo_surface_destroy (surface);
+  cr = cairo_create (priv->cr_surface);
+  cairo_set_user_data (cr, &clutter_cairo_texture_context_key,
+                      ctxt, clutter_cairo_texture_context_destroy);
 
   return cr;
 }
@@ -690,16 +751,13 @@ void
 clutter_cairo_texture_clear (ClutterCairoTexture *self)
 {
   ClutterCairoTexturePrivate *priv;
-  guint8 *data;
 
   g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self));
 
   priv = self->priv;
 
-  if (!priv->buffer)
+  if (!priv->cr_surface_data)
     return;
 
-  data = cogl_buffer_map (priv->buffer, COGL_BUFFER_ACCESS_WRITE);
-  memset (data, 0, priv->buffer_height * priv->rowstride);
-  cogl_buffer_unmap (priv->buffer);
+  memset (priv->cr_surface_data, 0, priv->height * priv->rowstride);
 }