cogl-bitmap: Encapsulate the CoglBitmap even internally
authorNeil Roberts <neil@linux.intel.com>
Wed, 7 Jul 2010 17:44:16 +0000 (18:44 +0100)
committerNeil Roberts <neil@linux.intel.com>
Thu, 15 Jul 2010 16:24:01 +0000 (17:24 +0100)
The CoglBitmap struct is now only defined within cogl-bitmap.c so that
all of its members can now only be accessed with accessor
functions. To get to the data pointer for the bitmap image you must
first call _cogl_bitmap_map and later call _cogl_bitmap_unmap. The map
function takes the same arguments as cogl_pixel_array_map so that
eventually we can make a bitmap optionally internally divert to a
pixel array.

There is a _cogl_bitmap_new_from_data function which constructs a new
bitmap object and takes ownership of the data pointer. The function
gets passed a destroy callback which gets called when the bitmap is
freed. This is similar to how gdk_pixbuf_new_from_data
works. Alternatively NULL can be passed for the destroy function which
means that the caller will manage the life of the pointer (but must
guarantee that it stays alive at least until the bitmap is
freed). This mechanism is used instead of the old approach of creating
a CoglBitmap struct on the stack and manually filling in the
members. It could also later be used to create a CoglBitmap that owns
a GdkPixbuf ref so that we don't necessarily have to copy the
GdkPixbuf data when converting to a bitmap.

There is also _cogl_bitmap_new_shared. This creates a bitmap using a
reference to another CoglBitmap for the data. This is a bit of a hack
but it is needed by the atlas texture backend which wants to divert
the set_region virtual to another texture but it needs to override the
format of the bitmap to ignore the premult flag.

19 files changed:
clutter/cogl/cogl/cogl-atlas-texture-private.h
clutter/cogl/cogl/cogl-atlas-texture.c
clutter/cogl/cogl/cogl-bitmap-fallback.c
clutter/cogl/cogl/cogl-bitmap-pixbuf.c
clutter/cogl/cogl/cogl-bitmap-private.h
clutter/cogl/cogl/cogl-bitmap.c
clutter/cogl/cogl/cogl-texture-2d-private.h
clutter/cogl/cogl/cogl-texture-2d-sliced-private.h
clutter/cogl/cogl/cogl-texture-2d-sliced.c
clutter/cogl/cogl/cogl-texture-2d.c
clutter/cogl/cogl/cogl-texture-3d-private.h
clutter/cogl/cogl/cogl-texture-3d.c
clutter/cogl/cogl/cogl-texture-private.h
clutter/cogl/cogl/cogl-texture-rectangle-private.h
clutter/cogl/cogl/cogl-texture-rectangle.c
clutter/cogl/cogl/cogl-texture.c
clutter/cogl/cogl/cogl.c
clutter/cogl/cogl/driver/gl/cogl-texture-driver.c
clutter/cogl/cogl/driver/gles/cogl-texture-driver.c

index a5ea448..f4fdb72 100644 (file)
@@ -57,7 +57,7 @@ GQuark
 _cogl_handle_atlas_texture_get_type (void);
 
 CoglHandle
-_cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
                                      CoglTextureFlags flags,
                                      CoglPixelFormat  internal_format);
 
index 3241bdc..3e913e2 100644 (file)
@@ -442,72 +442,57 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
                                             int             dst_y,
                                             unsigned int    dst_width,
                                             unsigned int    dst_height,
-                                            int             width,
-                                            int             height,
-                                            CoglPixelFormat format,
-                                            unsigned int    rowstride,
-                                            const guint8   *data)
+                                            CoglBitmap     *bmp)
 {
   _COGL_GET_CONTEXT (ctx, FALSE);
 
   /* Copy the central data */
-  if (!cogl_texture_set_region (ctx->atlas_texture,
-                                src_x, src_y,
-                                dst_x + atlas_tex->rectangle.x + 1,
-                                dst_y + atlas_tex->rectangle.y + 1,
-                                dst_width,
-                                dst_height,
-                                width, height,
-                                format,
-                                rowstride,
-                                data))
+  if (!_cogl_texture_set_region_from_bitmap (ctx->atlas_texture,
+                                             src_x, src_y,
+                                             dst_x + atlas_tex->rectangle.x + 1,
+                                             dst_y + atlas_tex->rectangle.y + 1,
+                                             dst_width,
+                                             dst_height,
+                                             bmp))
     return FALSE;
 
   /* Update the left edge pixels */
   if (dst_x == 0 &&
-      !cogl_texture_set_region (ctx->atlas_texture,
-                                src_x, src_y,
-                                atlas_tex->rectangle.x,
-                                dst_y + atlas_tex->rectangle.y + 1,
-                                1, dst_height,
-                                width, height,
-                                format, rowstride,
-                                data))
+      !_cogl_texture_set_region_from_bitmap (ctx->atlas_texture,
+                                             src_x, src_y,
+                                             atlas_tex->rectangle.x,
+                                             dst_y + atlas_tex->rectangle.y + 1,
+                                             1, dst_height,
+                                             bmp))
     return FALSE;
   /* Update the right edge pixels */
   if (dst_x + dst_width == atlas_tex->rectangle.width - 2 &&
-      !cogl_texture_set_region (ctx->atlas_texture,
-                                src_x + dst_width - 1, src_y,
-                                atlas_tex->rectangle.x +
-                                atlas_tex->rectangle.width - 1,
-                                dst_y + atlas_tex->rectangle.y + 1,
-                                1, dst_height,
-                                width, height,
-                                format, rowstride,
-                                data))
+      !_cogl_texture_set_region_from_bitmap (ctx->atlas_texture,
+                                             src_x + dst_width - 1, src_y,
+                                             atlas_tex->rectangle.x +
+                                             atlas_tex->rectangle.width - 1,
+                                             dst_y + atlas_tex->rectangle.y + 1,
+                                             1, dst_height,
+                                             bmp))
     return FALSE;
   /* Update the top edge pixels */
   if (dst_y == 0 &&
-      !cogl_texture_set_region (ctx->atlas_texture,
-                                src_x, src_y,
-                                dst_x + atlas_tex->rectangle.x + 1,
-                                atlas_tex->rectangle.y,
-                                dst_width, 1,
-                                width, height,
-                                format, rowstride,
-                                data))
+      !_cogl_texture_set_region_from_bitmap (ctx->atlas_texture,
+                                             src_x, src_y,
+                                             dst_x + atlas_tex->rectangle.x + 1,
+                                             atlas_tex->rectangle.y,
+                                             dst_width, 1,
+                                             bmp))
     return FALSE;
   /* Update the bottom edge pixels */
   if (dst_y + dst_height == atlas_tex->rectangle.height - 2 &&
-      !cogl_texture_set_region (ctx->atlas_texture,
-                                src_x, src_y + dst_height - 1,
-                                dst_x + atlas_tex->rectangle.x + 1,
-                                atlas_tex->rectangle.y +
-                                atlas_tex->rectangle.height - 1,
-                                dst_width, 1,
-                                width, height,
-                                format, rowstride,
-                                data))
+      !_cogl_texture_set_region_from_bitmap (ctx->atlas_texture,
+                                             src_x, src_y + dst_height - 1,
+                                             dst_x + atlas_tex->rectangle.x + 1,
+                                             atlas_tex->rectangle.y +
+                                             atlas_tex->rectangle.height - 1,
+                                             dst_width, 1,
+                                             bmp))
     return FALSE;
 
   return TRUE;
@@ -528,18 +513,27 @@ _cogl_atlas_texture_set_region (CoglTexture    *tex,
   /* If the texture is in the atlas then we need to copy the edge
      pixels to the border */
   if (atlas_tex->in_atlas)
-    /* Upload the data ignoring the premult bit */
-    return _cogl_atlas_texture_set_region_with_border (atlas_tex,
-                                                       src_x, src_y,
-                                                       dst_x, dst_y,
-                                                       dst_width, dst_height,
-                                                       bmp->width,
-                                                       bmp->height,
-                                                       bmp->format &
-                                                       ~COGL_PREMULT_BIT,
-                                                       bmp->rowstride,
-                                                       bmp->data);
+    {
+      gboolean ret;
+
+      bmp = _cogl_bitmap_new_shared (bmp,
+                                     _cogl_bitmap_get_format (bmp) &
+                                     ~COGL_PREMULT_BIT,
+                                     _cogl_bitmap_get_width (bmp),
+                                     _cogl_bitmap_get_height (bmp),
+                                     _cogl_bitmap_get_rowstride (bmp));
+
+      /* Upload the data ignoring the premult bit */
+      ret = _cogl_atlas_texture_set_region_with_border (atlas_tex,
+                                                        src_x, src_y,
+                                                        dst_x, dst_y,
+                                                        dst_width, dst_height,
+                                                        bmp);
 
+      cogl_object_unref (bmp);
+
+      return ret;
+    }
   else
     /* Otherwise we can just forward on to the sub texture */
     return _cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture,
@@ -909,21 +903,23 @@ _cogl_atlas_texture_reserve_space (CoglAtlasTexture    *new_sub_tex,
 }
 
 CoglHandle
-_cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
                                      CoglTextureFlags flags,
                                      CoglPixelFormat  internal_format)
 {
   CoglAtlasTexture *atlas_tex;
-  CoglBitmap       *bmp = (CoglBitmap *) bmp_handle;
-  CoglBitmap        dst_bmp;
-  gboolean          dst_bmp_owner;
+  CoglBitmap       *dst_bmp;
+  CoglBitmap       *override_bmp;
   GLenum            gl_intformat;
   GLenum            gl_format;
   GLenum            gl_type;
+  int               bmp_width;
+  int               bmp_height;
+  CoglPixelFormat   bmp_format;
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
-  g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
+  g_return_val_if_fail (cogl_is_bitmap (bmp), COGL_INVALID_HANDLE);
 
   /* Don't put textures in the atlas if the user has explicitly
      requested to disable it */
@@ -936,9 +932,13 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
   if (flags)
     return COGL_INVALID_HANDLE;
 
+  bmp_width = _cogl_bitmap_get_width (bmp);
+  bmp_height = _cogl_bitmap_get_height (bmp);
+  bmp_format = _cogl_bitmap_get_format (bmp);
+
   /* We can't atlas zero-sized textures because it breaks the atlas
      data structure */
-  if (bmp->width < 1 || bmp->height < 1)
+  if (bmp_width < 1 || bmp_height < 1)
     return COGL_INVALID_HANDLE;
 
   /* If we can't use FBOs or we can't read back texture data then it
@@ -948,9 +948,9 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
       !cogl_features_available (COGL_FEATURE_OFFSCREEN))
     return COGL_INVALID_HANDLE;
 
-  COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp->width, bmp->height);
+  COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp_width, bmp_height);
 
-  internal_format = _cogl_texture_determine_internal_format (bmp->format,
+  internal_format = _cogl_texture_determine_internal_format (bmp_format,
                                                              internal_format);
 
   /* If the texture is in a strange format then we can't use it */
@@ -968,8 +968,8 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
   atlas_tex = g_new (CoglAtlasTexture, 1);
   /* We need to fill in the texture size now because it is used in the
      reserve_space function below. We add two pixels for the border */
-  atlas_tex->rectangle.width = bmp->width + 2;
-  atlas_tex->rectangle.height = bmp->height + 2;
+  atlas_tex->rectangle.width = bmp_width + 2;
+  atlas_tex->rectangle.height = bmp_height + 2;
 
   /* Try to make some space in the atlas for the texture */
   if (!_cogl_atlas_texture_reserve_space (atlas_tex,
@@ -980,14 +980,14 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
       return COGL_INVALID_HANDLE;
     }
 
-  if (!_cogl_texture_prepare_for_upload (bmp,
-                                         internal_format,
-                                         &internal_format,
-                                         &dst_bmp,
-                                         &dst_bmp_owner,
-                                         &gl_intformat,
-                                         &gl_format,
-                                         &gl_type))
+  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                              internal_format,
+                                              &internal_format,
+                                              &gl_intformat,
+                                              &gl_format,
+                                              &gl_type);
+
+  if (dst_bmp == NULL)
     {
       _cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle);
       g_free (atlas_tex);
@@ -1001,24 +1001,29 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
     _cogl_atlas_texture_create_sub_texture (ctx->atlas_texture,
                                             &atlas_tex->rectangle);
 
+  /* Make another bitmap so that we can override the format */
+  override_bmp = _cogl_bitmap_new_shared (dst_bmp,
+                                          _cogl_bitmap_get_format (dst_bmp) &
+                                          ~COGL_PREMULT_BIT,
+                                          _cogl_bitmap_get_width (dst_bmp),
+                                          _cogl_bitmap_get_height (dst_bmp),
+                                          _cogl_bitmap_get_rowstride (dst_bmp));
+  cogl_object_unref (dst_bmp);
+
   /* Defer to set_region so that we can share the code for copying the
      edge pixels to the border. We don't want to pass the actual
      format of the converted texture because otherwise it will get
      unpremultiplied. */
   _cogl_atlas_texture_set_region_with_border (atlas_tex,
-                                              0, 0,
-                                              0, 0,
-                                              dst_bmp.width,
-                                              dst_bmp.height,
-                                              dst_bmp.width,
-                                              dst_bmp.height,
-                                              dst_bmp.format &
-                                              ~COGL_PREMULT_BIT,
-                                              dst_bmp.rowstride,
-                                              dst_bmp.data);
-
-  if (dst_bmp_owner)
-    g_free (dst_bmp.data);
+                                              0, /* src_x */
+                                              0, /* src_y */
+                                              0, /* dst_x */
+                                              0, /* dst_y */
+                                              bmp_width, /* dst_width */
+                                              bmp_height, /* dst_height */
+                                              override_bmp);
+
+  cogl_object_unref (override_bmp);
 
   return _cogl_atlas_texture_handle_new (atlas_tex);
 }
index a180298..4478c43 100644 (file)
@@ -337,52 +337,61 @@ _cogl_bitmap_fallback_can_premult (CoglPixelFormat format)
   return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32);
 }
 
-gboolean
-_cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
-                              CoglBitmap       *dst_bmp,
-                              CoglPixelFormat   dst_format)
+CoglBitmap *
+_cogl_bitmap_fallback_convert (CoglBitmap      *src_bmp,
+                               CoglPixelFormat  dst_format)
 {
-  guint8  *src;
-  guint8  *dst;
-  int      src_bpp;
-  int      dst_bpp;
-  int      x,y;
-  guint8   temp_rgba[4] = {0,0,0,0};
+  guint8          *src_data;
+  guint8          *dst_data;
+  guint8          *src;
+  guint8          *dst;
+  int              src_bpp;
+  int              dst_bpp;
+  int              src_rowstride;
+  int              dst_rowstride;
+  int              x,y;
+  guint8           temp_rgba[4] = {0,0,0,0};
+  int              width, height;
+  CoglPixelFormat  src_format;
+
+  src_format = _cogl_bitmap_get_format (src_bmp);
+  src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
+  width = _cogl_bitmap_get_width (src_bmp);
+  height = _cogl_bitmap_get_height (src_bmp);
 
   /* Make sure conversion supported */
-  if (!_cogl_bitmap_fallback_can_convert (bmp->format, dst_format))
-    return FALSE;
+  if (!_cogl_bitmap_fallback_can_convert (src_format, dst_format))
+    return NULL;
 
-  src_bpp = _cogl_get_format_bpp (bmp->format);
+  src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0);
+  if (src_data == NULL)
+    return NULL;
+
+  src_bpp = _cogl_get_format_bpp (src_format);
   dst_bpp = _cogl_get_format_bpp (dst_format);
 
   /* Initialize destination bitmap */
-  *dst_bmp = *bmp;
-  dst_bmp->rowstride = sizeof(guint8) * dst_bpp * dst_bmp->width;
+  dst_rowstride = sizeof(guint8) * dst_bpp * width;
   /* Copy the premult bit if the new format has an alpha channel */
   if ((dst_format & COGL_A_BIT))
-    dst_bmp->format = ((bmp->format & COGL_PREMULT_BIT) |
-                       (dst_format & COGL_UNPREMULT_MASK));
-  else
-    dst_bmp->format = dst_format;
+    dst_format = ((src_format & COGL_PREMULT_BIT) |
+                  (dst_format & COGL_UNPREMULT_MASK));
 
   /* Allocate a new buffer to hold converted data */
-  dst_bmp->data = g_malloc (sizeof(guint8)
-                           * dst_bmp->height
-                           * dst_bmp->rowstride);
+  dst_data = g_malloc (height * dst_rowstride);
 
   /* FIXME: Optimize */
-  for (y = 0; y < bmp->height; y++)
+  for (y = 0; y < height; y++)
     {
-      src = (guint8*)bmp->data      + y * bmp->rowstride;
-      dst = (guint8*)dst_bmp->data  + y * dst_bmp->rowstride;
+      src = src_data + y * src_rowstride;
+      dst = dst_data + y * dst_rowstride;
 
-      for (x = 0; x < bmp->width; x++)
+      for (x = 0; x < width; x++)
        {
          /* FIXME: Would be nice to at least remove this inner
            * branching, but not sure it can be done without
            * rewriting of the whole loop */
-         switch (bmp->format & COGL_UNPREMULT_MASK)
+          switch (src_format & COGL_UNPREMULT_MASK)
            {
            case COGL_PIXEL_FORMAT_G_8:
              _cogl_g_to_rgba (src, temp_rgba); break;
@@ -427,26 +436,46 @@ _cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
        }
     }
 
-  return TRUE;
+  _cogl_bitmap_unmap (src_bmp);
+
+  return _cogl_bitmap_new_from_data (dst_data,
+                                     dst_format,
+                                     width, height, dst_rowstride,
+                                     (CoglBitmapDestroyNotify) g_free,
+                                     NULL);
 }
 
 gboolean
 _cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
 {
-  guint8  *p;
-  int      x,y;
+  guint8          *p, *data;
+  int              x,y;
+  CoglPixelFormat  format;
+  int              width, height;
+  int              rowstride;
+
+  format = _cogl_bitmap_get_format (bmp);
+  width = _cogl_bitmap_get_width (bmp);
+  height = _cogl_bitmap_get_height (bmp);
+  rowstride = _cogl_bitmap_get_rowstride (bmp);
 
   /* Make sure format supported for un-premultiplication */
-  if (!_cogl_bitmap_fallback_can_unpremult (bmp->format))
+  if (!_cogl_bitmap_fallback_can_unpremult (format))
+    return FALSE;
+
+  if ((data = _cogl_bitmap_map (bmp,
+                                COGL_BUFFER_ACCESS_READ |
+                                COGL_BUFFER_ACCESS_WRITE,
+                                0)) == NULL)
     return FALSE;
 
-  for (y = 0; y < bmp->height; y++)
+  for (y = 0; y < height; y++)
     {
-      p = (guint8*) bmp->data + y * bmp->rowstride;
+      p = (guint8*) data + y * rowstride;
 
-      if (bmp->format & COGL_AFIRST_BIT)
+      if (format & COGL_AFIRST_BIT)
         {
-          for (x = 0; x < bmp->width; x++)
+          for (x = 0; x < width; x++)
             {
               if (p[0] == 0)
                 _cogl_unpremult_alpha_0 (p);
@@ -457,7 +486,7 @@ _cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
         }
       else
         {
-          for (x = 0; x < bmp->width; x++)
+          for (x = 0; x < width; x++)
             {
               if (p[3] == 0)
                 _cogl_unpremult_alpha_0 (p);
@@ -468,7 +497,9 @@ _cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
         }
     }
 
-  bmp->format &= ~COGL_PREMULT_BIT;
+  _cogl_bitmap_unmap (bmp);
+
+  _cogl_bitmap_set_format (bmp, format & ~COGL_PREMULT_BIT);
 
   return TRUE;
 }
@@ -476,20 +507,34 @@ _cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
 gboolean
 _cogl_bitmap_fallback_premult (CoglBitmap *bmp)
 {
-  guint8  *p;
-  int      x,y;
+  guint8          *p, *data;
+  int              x,y;
+  CoglPixelFormat  format;
+  int              width, height;
+  int              rowstride;
+
+  format = _cogl_bitmap_get_format (bmp);
+  width = _cogl_bitmap_get_width (bmp);
+  height = _cogl_bitmap_get_height (bmp);
+  rowstride = _cogl_bitmap_get_rowstride (bmp);
 
   /* Make sure format supported for un-premultiplication */
-  if (!_cogl_bitmap_fallback_can_premult (bmp->format))
+  if (!_cogl_bitmap_fallback_can_premult (format))
     return FALSE;
 
-  for (y = 0; y < bmp->height; y++)
+  if ((data = _cogl_bitmap_map (bmp,
+                                COGL_BUFFER_ACCESS_READ |
+                                COGL_BUFFER_ACCESS_WRITE,
+                                0)) == NULL)
+    return FALSE;
+
+  for (y = 0; y < height; y++)
     {
-      p = (guint8*) bmp->data + y * bmp->rowstride;
+      p = (guint8*) data + y * rowstride;
 
-      if (bmp->format & COGL_AFIRST_BIT)
+      if (format & COGL_AFIRST_BIT)
         {
-          for (x = 0; x < bmp->width; x++)
+          for (x = 0; x < width; x++)
             {
               _cogl_premult_alpha_first (p);
               p += 4;
@@ -497,7 +542,7 @@ _cogl_bitmap_fallback_premult (CoglBitmap *bmp)
         }
       else
         {
-          x = bmp->width;
+          x = width;
 
 #ifdef COGL_USE_PREMULT_SSE2
 
@@ -522,14 +567,15 @@ _cogl_bitmap_fallback_premult (CoglBitmap *bmp)
         }
     }
 
-  bmp->format |= COGL_PREMULT_BIT;
+  _cogl_bitmap_unmap (bmp);
+
+  _cogl_bitmap_set_format (bmp, format | COGL_PREMULT_BIT);
 
   return TRUE;
 }
 
-gboolean
-_cogl_bitmap_fallback_from_file (CoglBitmap  *bmp,
-                                const char  *filename)
+CoglBitmap *
+_cogl_bitmap_fallback_from_file (const char  *filename)
 {
   /* FIXME: use jpeglib, libpng, etc. manually maybe */
   return FALSE;
index 9d2e0dd..bda210f 100644 (file)
@@ -55,12 +55,11 @@ _cogl_bitmap_can_premult (CoglPixelFormat format)
   return FALSE;
 }
 
-gboolean
-_cogl_bitmap_convert (const CoglBitmap *bmp,
-                     CoglBitmap       *dst_bmp,
+CoglBitmap *
+_cogl_bitmap_convert (CoglBitmap *bmp,
                      CoglPixelFormat   dst_format)
 {
-  return FALSE;
+  return NULL;
 }
 
 gboolean
@@ -92,12 +91,10 @@ _cogl_bitmap_get_size_from_file (const char *filename,
 }
 
 /* the error does not contain the filename as the caller already has it */
-gboolean
-_cogl_bitmap_from_file (CoglBitmap  *bmp,
-                       const char  *filename,
+CoglBitmap *
+_cogl_bitmap_from_file (const char  *filename,
                        GError     **error)
 {
-  g_assert (bmp != NULL);
   g_assert (filename != NULL);
   g_assert (error == NULL || *error == NULL);
 
@@ -110,7 +107,7 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
       /* doesn't exist, not readable, etc. */
       g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED,
                    "%s", g_strerror (save_errno));
-      return FALSE;
+      return NULL;
     }
 
   /* Unknown images would be cleanly caught as zero width/height below, but try
@@ -122,7 +119,7 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
       CFRelease (image_source);
       g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_UNKNOWN_TYPE,
                    "Unknown image type");
-      return FALSE;
+      return NULL;
     }
   CFRelease (type);
 
@@ -137,7 +134,7 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
       CFRelease (image);
       g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_CORRUPT_IMAGE,
                    "Image has zero width or height");
-      return FALSE;
+      return NULL;
     }
 
   /* allocate buffer big enough to hold pixel data */
@@ -160,13 +157,12 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
   CGContextRelease (bitmap_context);
 
   /* store bitmap info */
-  bmp->data = out_data;
-  bmp->format = COGL_PIXEL_FORMAT_ARGB_8888;
-  bmp->width = width;
-  bmp->height = height;
-  bmp->rowstride = rowstride;
-
-  return TRUE;
+  return _cogl_bitmap_new_from_data (out_data,
+                                     COGL_PIXEL_FORMAT_ARGB_8888,
+                                     width, height,
+                                     rowstride,
+                                     (CoglBitmapDestroyNotify) g_free,
+                                     NULL);
 }
 
 #elif defined(USE_GDKPIXBUF)
@@ -184,9 +180,8 @@ _cogl_bitmap_get_size_from_file (const char *filename,
   return FALSE;
 }
 
-gboolean
-_cogl_bitmap_from_file (CoglBitmap   *bmp,
-                       const char   *filename,
+CoglBitmap *
+_cogl_bitmap_from_file (const char   *filename,
                        GError      **error)
 {
   GdkPixbuf        *pixbuf;
@@ -206,9 +201,6 @@ _cogl_bitmap_from_file (CoglBitmap   *bmp,
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  if (bmp == NULL)
-    return FALSE;
-
   /* Load from file using GdkPixbuf */
   pixbuf = gdk_pixbuf_new_from_file (filename, error);
   if (pixbuf == NULL)
@@ -272,16 +264,16 @@ _cogl_bitmap_from_file (CoglBitmap   *bmp,
   g_object_unref (pixbuf);
 
   /* Store bitmap info */
-  bmp->data = out_data; /* The stored data the same alignment constraints as a
-                         * gdkpixbuf but stores a full rowstride in the last
-                         * scanline
-                         */
-  bmp->format = pixel_format;
-  bmp->width = width;
-  bmp->height = height;
-  bmp->rowstride = rowstride;
-
-  return TRUE;
+  /* The stored data the same alignment constraints as a gdkpixbuf but
+   * stores a full rowstride in the last scanline
+   */
+  return _cogl_bitmap_new_from_data (out_data,
+                                     pixel_format,
+                                     width,
+                                     height,
+                                     rowstride,
+                                     (CoglBitmapDestroyNotify) g_free,
+                                     NULL);
 }
 
 #else
@@ -302,11 +294,11 @@ _cogl_bitmap_get_size_from_file (const char *filename,
   return TRUE;
 }
 
-gboolean
-_cogl_bitmap_from_file (CoglBitmap  *bmp,
-                       const char  *filename,
+CoglBitmap *
+_cogl_bitmap_from_file (const char  *filename,
                        GError     **error)
 {
+  CoglBitmap *bmp;
   int      stb_pixel_format;
   int      width;
   int      height;
@@ -314,9 +306,6 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  if (bmp == NULL)
-    return FALSE;
-
   /* Load from file using stb */
   pixels = stbi_load (filename,
                       &width, &height, &stb_pixel_format,
@@ -325,14 +314,15 @@ _cogl_bitmap_from_file (CoglBitmap  *bmp,
     return FALSE;
 
   /* Store bitmap info */
-  bmp->data = g_memdup (pixels, height * width * 4);
-  bmp->format = COGL_PIXEL_FORMAT_RGBA_8888;
-  bmp->width = width;
-  bmp->height = height;
-  bmp->rowstride = width * 4;
+  bmp = _cogl_bitmap_new_from_data (g_memdup (pixels, height * width * 4),
+                                    COGL_PIXEL_FORMAT_RGBA_8888,
+                                    width, height,
+                                    width * 4,
+                                    (CoglBitmapDestroyNotify) g_free,
+                                    NULL);
 
   free (pixels);
 
-  return TRUE;
+  return bmp;
 }
 #endif
index cc7cc83..7aefee6 100644 (file)
 #include <glib.h>
 
 #include "cogl-handle.h"
+#include "cogl-buffer.h"
 
-struct _CoglBitmap
-{
-  CoglHandleObject _parent;
-  guint8          *data;
-  CoglPixelFormat  format;
-  int              width;
-  int              height;
-  int              rowstride;
-};
+/*
+ * CoglBitmapDestroyNotify:
+ * @data: The image data
+ * @destroy_data: The callback closure data that was given to
+ *   _cogl_bitmap_new_from_data().
+ *
+ * Function prototype that is used to destroy the bitmap data when
+ * _cogl_bitmap_new_from_data() is called.
+ */
+typedef void (* CoglBitmapDestroyNotify) (guint8 *data, void *destroy_data);
+
+/*
+ * _cogl_bitmap_new_from_data:
+ * @data: A pointer to the data. The bitmap will take ownership of this data.
+ * @format: The format of the pixel data.
+ * @width: The width of the bitmap.
+ * @height: The height of the bitmap.
+ * @rowstride: The rowstride of the bitmap (the number of bytes from
+ *   the start of one row of the bitmap to the next).
+ * @destroy_fn: A function to be called when the bitmap is
+ *   destroyed. This should free @data. %NULL can be used instead if
+ *   no free is needed.
+ * @destroy_fn_data: This pointer will get passed to @destroy_fn.
+ *
+ * Creates a bitmap using some existing data. The data is not copied
+ * so the bitmap will take ownership of the data pointer. When the
+ * bitmap is freed @destroy_fn will be called to free the data.
+ *
+ * Return value: A new %CoglBitmap.
+ */
+CoglBitmap *
+_cogl_bitmap_new_from_data (guint8                  *data,
+                            CoglPixelFormat          format,
+                            int                      width,
+                            int                      height,
+                            int                      rowstride,
+                            CoglBitmapDestroyNotify  destroy_fn,
+                            gpointer                 destroy_fn_data);
+
+/* The idea of this function is that it will create a bitmap that
+   shares the actual data with another bitmap. This is needed for the
+   atlas texture backend because it needs upload a bitmap to a sub
+   texture but override the format so that it ignores the premult
+   flag. */
+CoglBitmap *
+_cogl_bitmap_new_shared (CoglBitmap      *shared_bmp,
+                         CoglPixelFormat  format,
+                         int              width,
+                         int              height,
+                         int              rowstride);
 
 gboolean
 _cogl_bitmap_can_convert (CoglPixelFormat src, CoglPixelFormat dst);
@@ -58,13 +100,11 @@ _cogl_bitmap_can_premult (CoglPixelFormat format);
 gboolean
 _cogl_bitmap_fallback_can_premult (CoglPixelFormat format);
 
-gboolean
-_cogl_bitmap_convert (const CoglBitmap *bmp,
-                     CoglBitmap       *dst_bmp,
+CoglBitmap *
+_cogl_bitmap_convert (CoglBitmap *bmp,
                      CoglPixelFormat   dst_format);
-gboolean
-_cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
-                              CoglBitmap       *dst_bmp,
+CoglBitmap *
+_cogl_bitmap_fallback_convert (CoglBitmap *bmp,
                               CoglPixelFormat   dst_format);
 
 gboolean
@@ -79,22 +119,19 @@ _cogl_bitmap_premult (CoglBitmap *dst_bmp);
 gboolean
 _cogl_bitmap_fallback_premult (CoglBitmap *dst_bmp);
 
-gboolean
-_cogl_bitmap_from_file (CoglBitmap  *bmp,
-                       const char *filename,
+CoglBitmap *
+_cogl_bitmap_from_file (const char *filename,
                        GError     **error);
 
-gboolean
-_cogl_bitmap_fallback_from_file (CoglBitmap  *bmp,
-                                const char *filename);
+CoglBitmap *
+_cogl_bitmap_fallback_from_file (const char *filename);
 
 gboolean
 _cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
                                      CoglPixelFormat  dst_format);
 
-gboolean
-_cogl_bitmap_convert_format_and_premult (const CoglBitmap *bmp,
-                                         CoglBitmap       *dst_bmp,
+CoglBitmap *
+_cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
                                          CoglPixelFormat   dst_format);
 
 void
@@ -112,4 +149,28 @@ _cogl_bitmap_get_size_from_file (const char *filename,
                                  int        *width,
                                  int        *height);
 
+CoglPixelFormat
+_cogl_bitmap_get_format (CoglBitmap *bitmap);
+
+void
+_cogl_bitmap_set_format (CoglBitmap *bitmap,
+                         CoglPixelFormat format);
+
+int
+_cogl_bitmap_get_width (CoglBitmap *bitmap);
+
+int
+_cogl_bitmap_get_height (CoglBitmap *bitmap);
+
+int
+_cogl_bitmap_get_rowstride (CoglBitmap *bitmap);
+
+guint8 *
+_cogl_bitmap_map (CoglBitmap *bitmap,
+                  CoglBufferAccess access,
+                  CoglBufferMapHint hints);
+
+void
+_cogl_bitmap_unmap (CoglBitmap *bitmap);
+
 #endif /* __COGL_BITMAP_H */
index 5514092..3131777 100644 (file)
 
 #include <string.h>
 
+struct _CoglBitmap
+{
+  CoglHandleObject         _parent;
+  CoglPixelFormat          format;
+  int                      width;
+  int                      height;
+  int                      rowstride;
+
+  guint8                  *data;
+  CoglBitmapDestroyNotify  destroy_fn;
+  void                    *destroy_fn_data;
+
+  gboolean                 mapped;
+
+  /* If this is non-null then 'data' is ignored and instead it is
+     fetched from this shared bitmap. */
+  CoglBitmap              *shared_bmp;
+};
+
 static void _cogl_bitmap_free (CoglBitmap *bmp);
 
 COGL_OBJECT_DEFINE (Bitmap, bitmap);
@@ -38,8 +57,15 @@ COGL_OBJECT_DEFINE (Bitmap, bitmap);
 static void
 _cogl_bitmap_free (CoglBitmap *bmp)
 {
-  g_free (bmp->data);
-  g_free (bmp);
+  g_assert (!bmp->mapped);
+
+  if (bmp->destroy_fn)
+    bmp->destroy_fn (bmp->data, bmp->destroy_fn_data);
+
+  if (bmp->shared_bmp)
+    cogl_object_unref (bmp->shared_bmp);
+
+  g_slice_free (CoglBitmap, bmp);
 }
 
 int
@@ -83,45 +109,65 @@ _cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
   return TRUE;
 }
 
-gboolean
-_cogl_bitmap_convert_format_and_premult (const CoglBitmap *bmp,
-                                         CoglBitmap       *dst_bmp,
+CoglBitmap *
+_cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
                                          CoglPixelFormat   dst_format)
 {
+  CoglPixelFormat src_format = _cogl_bitmap_get_format (bmp);
+  CoglBitmap *dst_bmp;
+
   /* Is base format different (not considering premult status)? */
-  if ((bmp->format & COGL_UNPREMULT_MASK) !=
+  if ((src_format & COGL_UNPREMULT_MASK) !=
       (dst_format & COGL_UNPREMULT_MASK))
     {
       /* Try converting using imaging library */
-      if (!_cogl_bitmap_convert (bmp, dst_bmp, dst_format))
+      if ((dst_bmp = _cogl_bitmap_convert (bmp, dst_format)) == NULL)
         {
           /* ... or try fallback */
-          if (!_cogl_bitmap_fallback_convert (bmp, dst_bmp, dst_format))
-            return FALSE;
+          if ((dst_bmp = _cogl_bitmap_fallback_convert (bmp,
+                                                        dst_format)) == NULL)
+            return NULL;
         }
     }
   else
     {
+      int rowstride = _cogl_bitmap_get_rowstride (bmp);
+      int height = _cogl_bitmap_get_height (bmp);
+      guint8 *data;
+
       /* Copy the bitmap so that we can premultiply in-place */
-      *dst_bmp = *bmp;
-      dst_bmp->data = g_memdup (bmp->data, bmp->rowstride * bmp->height);
+
+      if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)) == NULL)
+        return NULL;
+
+      dst_bmp = _cogl_bitmap_new_from_data (g_memdup (data, height * rowstride),
+                                            src_format,
+                                            _cogl_bitmap_get_width (bmp),
+                                            height,
+                                            rowstride,
+                                            (CoglBitmapDestroyNotify) g_free,
+                                            NULL);
+
+      _cogl_bitmap_unmap (bmp);
     }
 
+  src_format = _cogl_bitmap_get_format (dst_bmp);
+
   /* We only need to do a premult conversion if both formats have an
      alpha channel. If we're converting from RGB to RGBA then the
      alpha will have been filled with 255 so the premult won't do
      anything or if we are converting from RGBA to RGB we're losing
      information so either converting or not will be wrong for
      transparent pixels */
-  if ((dst_bmp->format & COGL_A_BIT) == COGL_A_BIT &&
+  if ((src_format & COGL_A_BIT) == COGL_A_BIT &&
       (dst_format & COGL_A_BIT) == COGL_A_BIT &&
       !_cogl_bitmap_convert_premult_status (dst_bmp, dst_format))
     {
-      g_free (dst_bmp->data);
-      return FALSE;
+      cogl_object_unref (dst_bmp);
+      return NULL;
     }
 
-  return TRUE;
+  return dst_bmp;
 }
 
 void
@@ -143,14 +189,24 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
   g_assert (src->format == dst->format);
   bpp = _cogl_get_format_bpp (src->format);
 
-  srcdata = src->data + src_y * src->rowstride + src_x * bpp;
-  dstdata = dst->data + dst_y * dst->rowstride + dst_x * bpp;
-
-  for (line=0; line<height; ++line)
+  if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0)))
     {
-      memcpy (dstdata, srcdata, width * bpp);
-      srcdata += src->rowstride;
-      dstdata += dst->rowstride;
+      if ((dstdata = _cogl_bitmap_map (dst, COGL_BUFFER_ACCESS_WRITE, 0)))
+        {
+          srcdata += src_y * src->rowstride + src_x * bpp;
+          dstdata += dst_y * dst->rowstride + dst_x * bpp;
+
+          for (line=0; line<height; ++line)
+            {
+              memcpy (dstdata, srcdata, width * bpp);
+              srcdata += src->rowstride;
+              dstdata += dst->rowstride;
+            }
+
+          _cogl_bitmap_unmap (dst);
+        }
+
+      _cogl_bitmap_unmap (src);
     }
 }
 
@@ -163,29 +219,88 @@ cogl_bitmap_get_size_from_file (const char *filename,
 }
 
 CoglBitmap *
+_cogl_bitmap_new_from_data (guint8                  *data,
+                            CoglPixelFormat          format,
+                            int                      width,
+                            int                      height,
+                            int                      rowstride,
+                            CoglBitmapDestroyNotify  destroy_fn,
+                            void                    *destroy_fn_data)
+{
+  CoglBitmap *bmp = g_slice_new (CoglBitmap);
+
+  bmp->format = format;
+  bmp->width = width;
+  bmp->height = height;
+  bmp->rowstride = rowstride;
+  bmp->data = data;
+  bmp->destroy_fn = destroy_fn;
+  bmp->destroy_fn_data = destroy_fn_data;
+  bmp->mapped = FALSE;
+  bmp->shared_bmp = NULL;
+
+  return _cogl_bitmap_object_new (bmp);
+}
+
+CoglBitmap *
+_cogl_bitmap_new_shared (CoglBitmap              *shared_bmp,
+                         CoglPixelFormat          format,
+                         int                      width,
+                         int                      height,
+                         int                      rowstride)
+{
+  CoglBitmap *bmp = _cogl_bitmap_new_from_data (NULL, /* data */
+                                                format,
+                                                width,
+                                                height,
+                                                rowstride,
+                                                NULL, /* destroy_fn */
+                                                NULL /* destroy_fn_data */);
+
+  bmp->shared_bmp = cogl_object_ref (shared_bmp);
+
+  return bmp;
+}
+
+CoglBitmap *
 cogl_bitmap_new_from_file (const char  *filename,
                            GError     **error)
 {
-  CoglBitmap   bmp;
-  CoglBitmap  *ret;
+  CoglBitmap *bmp;
 
   g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
 
-  /* Try loading with imaging backend */
-  if (!_cogl_bitmap_from_file (&bmp, filename, error))
+  if ((bmp = _cogl_bitmap_from_file (filename, error)) == NULL)
     {
       /* Try fallback */
-      if (!_cogl_bitmap_fallback_from_file (&bmp, filename))
-       return NULL;
-      else if (error && *error)
-       {
-         g_error_free (*error);
-         *error = NULL;
-       }
+      if ((bmp = _cogl_bitmap_fallback_from_file (filename))
+          && error && *error)
+        {
+          g_error_free (*error);
+          *error = NULL;
+        }
     }
 
-  ret = g_memdup (&bmp, sizeof (CoglBitmap));
-  return _cogl_bitmap_object_new (ret);
+  return bmp;
+}
+
+CoglPixelFormat
+_cogl_bitmap_get_format (CoglBitmap *bitmap)
+{
+  return bitmap->format;
+}
+
+void
+_cogl_bitmap_set_format (CoglBitmap *bitmap,
+                         CoglPixelFormat format)
+{
+  bitmap->format = format;
+}
+
+int
+_cogl_bitmap_get_width (CoglBitmap *bitmap)
+{
+  return bitmap->width;
 }
 
 GQuark
@@ -193,3 +308,46 @@ cogl_bitmap_error_quark (void)
 {
   return g_quark_from_static_string ("cogl-bitmap-error-quark");
 }
+
+int
+_cogl_bitmap_get_height (CoglBitmap *bitmap)
+{
+  return bitmap->height;
+}
+
+int
+_cogl_bitmap_get_rowstride (CoglBitmap *bitmap)
+{
+  return bitmap->rowstride;
+}
+
+guint8 *
+_cogl_bitmap_map (CoglBitmap *bitmap,
+                  CoglBufferAccess access,
+                  CoglBufferMapHint hints)
+{
+  /* Divert to another bitmap if this data is shared */
+  if (bitmap->shared_bmp)
+    return _cogl_bitmap_map (bitmap->shared_bmp, access, hints);
+
+  g_assert (!bitmap->mapped);
+  bitmap->mapped = TRUE;
+
+  /* Currently the bitmap is always in regular memory so we can just
+     directly return the pointer */
+  return bitmap->data;
+}
+
+void
+_cogl_bitmap_unmap (CoglBitmap *bitmap)
+{
+  /* Divert to another bitmap if this data is shared */
+  if (bitmap->shared_bmp)
+    return _cogl_bitmap_unmap (bitmap->shared_bmp);
+
+  g_assert (bitmap->mapped);
+  bitmap->mapped = FALSE;
+
+  /* Currently the bitmap is always in regular memory so we don't need
+     to do anything */
+}
index 705ed39..00bc88d 100644 (file)
@@ -65,7 +65,7 @@ _cogl_texture_2d_new_with_size (unsigned int     width,
                                 CoglPixelFormat  internal_format);
 
 CoglHandle
-_cogl_texture_2d_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format);
 
index 09a70e2..462c405 100644 (file)
@@ -82,7 +82,7 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint           gl_handle,
                                           CoglPixelFormat  format);
 
 CoglHandle
-_cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap      *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat  internal_format);
 
index 2161144..537a5f0 100644 (file)
@@ -224,17 +224,19 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
                                       GLenum               gl_format,
                                       GLenum               gl_type)
 {
-  CoglSpan  *x_span;
-  CoglSpan  *y_span;
-  GLuint     gl_handle;
-  int        bpp;
-  int        x, y;
-  guint8    *waste_buf;
+  CoglSpan        *x_span;
+  CoglSpan        *y_span;
+  GLuint           gl_handle;
+  int              bpp;
+  int              x, y;
+  guint8          *waste_buf;
+  CoglPixelFormat  bmp_format;
 
-  bpp = _cogl_get_format_bpp (bmp->format);
+  bmp_format = _cogl_bitmap_get_format (bmp);
+  bpp = _cogl_get_format_bpp (bmp_format);
 
   waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
-                                                             bmp->format);
+                                                             bmp_format);
 
   /* Iterate vertical slices */
   for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
@@ -268,10 +270,17 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
           /* Keep a copy of the first pixel if needed */
           if (tex_2ds->first_pixels)
             {
-              memcpy (tex_2ds->first_pixels[slice_num].data,
-                      bmp->data + x_span->start * bpp
-                      + y_span->start * bmp->rowstride,
-                      bpp);
+              guint8 *data;
+
+              if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
+                {
+                  memcpy (tex_2ds->first_pixels[slice_num].data,
+                          data + x_span->start * bpp
+                          + y_span->start * _cogl_bitmap_get_rowstride (bmp),
+                          bpp);
+                  _cogl_bitmap_unmap (bmp);
+                }
+
               tex_2ds->first_pixels[slice_num].gl_format = gl_format;
               tex_2ds->first_pixels[slice_num].gl_type = gl_type;
             }
@@ -279,67 +288,85 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
           /* Fill the waste with a copies of the rightmost pixels */
           if (x_span->waste > 0)
             {
-              const guint8 *src = bmp->data
-                + y_span->start * bmp->rowstride
-                + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
-              guint8 *dst = waste_buf;
-              unsigned int wx, wy;
+              int bmp_rowstride = _cogl_bitmap_get_rowstride (bmp);
+              guint8 *bmp_data = _cogl_bitmap_map (bmp,
+                                                   COGL_BUFFER_ACCESS_READ, 0);
 
-              for (wy = 0; wy < y_span->size - y_span->waste; wy++)
+              if (bmp_data)
                 {
-                  for (wx = 0; wx < x_span->waste; wx++)
+                  const guint8 *src = bmp_data
+                    + y_span->start * bmp_rowstride
+                    + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
+                  guint8 *dst = waste_buf;
+                  unsigned int wx, wy;
+
+                  for (wy = 0; wy < y_span->size - y_span->waste; wy++)
                     {
-                      memcpy (dst, src, bpp);
-                      dst += bpp;
+                      for (wx = 0; wx < x_span->waste; wx++)
+                        {
+                          memcpy (dst, src, bpp);
+                          dst += bpp;
+                        }
+                      src += bmp_rowstride;
                     }
-                  src += bmp->rowstride;
-                }
 
-              _cogl_texture_driver_prep_gl_for_pixels_upload (
-                                                        x_span->waste * bpp,
-                                                        bpp);
-
-              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
-                                   x_span->size - x_span->waste,
-                                   0,
-                                   x_span->waste,
-                                   y_span->size - y_span->waste,
-                                   gl_format, gl_type,
-                                   waste_buf) );
+                  _cogl_bitmap_unmap (bmp);
+
+                  _cogl_texture_driver_prep_gl_for_pixels_upload (
+                                                          x_span->waste * bpp,
+                                                          bpp);
+
+                  GE( glTexSubImage2D (tex_2ds->gl_target, 0,
+                                       x_span->size - x_span->waste,
+                                       0,
+                                       x_span->waste,
+                                       y_span->size - y_span->waste,
+                                       gl_format, gl_type,
+                                       waste_buf) );
+                }
             }
 
           if (y_span->waste > 0)
             {
-              const guint8 *src = bmp->data
-                + ((y_span->start + y_span->size - y_span->waste - 1)
-                   * bmp->rowstride)
-                + x_span->start * bpp;
-              guint8 *dst = waste_buf;
-              unsigned int wy, wx;
-
-              for (wy = 0; wy < y_span->waste; wy++)
-                {
-                  memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
-                  dst += (x_span->size - x_span->waste) * bpp;
+              int bmp_rowstride = _cogl_bitmap_get_rowstride (bmp);
+              guint8 *bmp_data = _cogl_bitmap_map (bmp,
+                                                   COGL_BUFFER_ACCESS_READ, 0);
 
-                  for (wx = 0; wx < x_span->waste; wx++)
+              if (bmp_data)
+                {
+                  const guint8 *src = bmp_data
+                    + ((y_span->start + y_span->size - y_span->waste - 1)
+                       * bmp_rowstride)
+                    + x_span->start * bpp;
+                  guint8 *dst = waste_buf;
+                  unsigned int wy, wx;
+
+                  for (wy = 0; wy < y_span->waste; wy++)
                     {
-                      memcpy (dst, dst - bpp, bpp);
-                      dst += bpp;
+                      memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
+                      dst += (x_span->size - x_span->waste) * bpp;
+
+                      for (wx = 0; wx < x_span->waste; wx++)
+                        {
+                          memcpy (dst, dst - bpp, bpp);
+                          dst += bpp;
+                        }
                     }
-                }
 
-              _cogl_texture_driver_prep_gl_for_pixels_upload (
-                                                        x_span->size * bpp,
-                                                        bpp);
-
-              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
-                                   0,
-                                   y_span->size - y_span->waste,
-                                   x_span->size,
-                                   y_span->waste,
-                                   gl_format, gl_type,
-                                   waste_buf) );
+                  _cogl_bitmap_unmap (bmp);
+
+                  _cogl_texture_driver_prep_gl_for_pixels_upload (
+                                                           x_span->size * bpp,
+                                                           bpp);
+
+                  GE( glTexSubImage2D (tex_2ds->gl_target, 0,
+                                       0,
+                                       y_span->size - y_span->waste,
+                                       x_span->size,
+                                       y_span->waste,
+                                       gl_format, gl_type,
+                                       waste_buf) );
+                }
             }
         }
     }
@@ -374,11 +401,13 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
   int               inter_w = 0, inter_h = 0;
   int               local_x = 0, local_y = 0;
   guint8           *waste_buf;
+  CoglPixelFormat   source_format;
 
-  bpp = _cogl_get_format_bpp (source_bmp->format);
+  source_format = _cogl_bitmap_get_format (source_bmp);
+  bpp = _cogl_get_format_bpp (source_format);
 
   waste_buf =
-    _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, source_bmp->format);
+    _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, source_format);
 
   /* Iterate vertical spans */
   for (source_y = src_y,
@@ -457,10 +486,18 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
           /* Keep a copy of the first pixel if needed */
           if (tex_2ds->first_pixels && local_x == 0 && local_y == 0)
             {
-              memcpy (tex_2ds->first_pixels[slice_num].data,
-                      source_bmp->data + source_x * bpp
-                      + source_y * source_bmp->rowstride,
-                      bpp);
+              guint8 *data;
+
+              if ((data = _cogl_bitmap_map (source_bmp,
+                                            COGL_BUFFER_ACCESS_READ, 0)))
+                {
+                  memcpy (tex_2ds->first_pixels[slice_num].data,
+                          data + source_x * bpp
+                          + source_y * _cogl_bitmap_get_rowstride (source_bmp),
+                          bpp);
+                  _cogl_bitmap_unmap (source_bmp);
+                }
+
               tex_2ds->first_pixels[slice_num].gl_format = source_gl_format;
               tex_2ds->first_pixels[slice_num].gl_type = source_gl_type;
             }
@@ -472,42 +509,51 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
               && local_x < x_span->size - x_span->waste
               && local_x + inter_w >= x_span->size - x_span->waste)
             {
-              const guint8 *src;
-              guint8 *dst;
-              unsigned int wx, wy;
+              int bmp_rowstride = _cogl_bitmap_get_rowstride (source_bmp);
+              guint8 *bmp_data = _cogl_bitmap_map (source_bmp,
+                                                   COGL_BUFFER_ACCESS_READ, 0);
 
-              src = source_bmp->data
-                + (src_y +  ((int)y_iter.intersect_start)
-                   - dst_y)
-                * source_bmp->rowstride
-                + (src_x + x_span->start + x_span->size - x_span->waste
-                   - dst_x - 1)
-                * bpp;
+              if (bmp_data)
+                {
+                  const guint8 *src;
+                  guint8 *dst;
+                  unsigned int wx, wy;
 
-              dst = waste_buf;
+                  src = bmp_data
+                    + (src_y +  ((int)y_iter.intersect_start)
+                       - dst_y)
+                    * bmp_rowstride
+                    + (src_x + x_span->start + x_span->size - x_span->waste
+                       - dst_x - 1)
+                    * bpp;
 
-              for (wy = 0; wy < inter_h; wy++)
-                {
-                  for (wx = 0; wx < x_span->waste; wx++)
+                  dst = waste_buf;
+
+                  for (wy = 0; wy < inter_h; wy++)
                     {
-                      memcpy (dst, src, bpp);
-                      dst += bpp;
+                      for (wx = 0; wx < x_span->waste; wx++)
+                        {
+                          memcpy (dst, src, bpp);
+                          dst += bpp;
+                        }
+                      src += bmp_rowstride;
                     }
-                  src += source_bmp->rowstride;
-                }
 
-              _cogl_texture_driver_prep_gl_for_pixels_upload (
-                                                        x_span->waste * bpp,
-                                                        bpp);
-
-              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
-                                   x_span->size - x_span->waste,
-                                   local_y,
-                                   x_span->waste,
-                                   inter_h,
-                                   source_gl_format,
-                                   source_gl_type,
-                                   waste_buf) );
+                  _cogl_bitmap_unmap (source_bmp);
+
+                  _cogl_texture_driver_prep_gl_for_pixels_upload (
+                                                           x_span->waste * bpp,
+                                                           bpp);
+
+                  GE( glTexSubImage2D (tex_2ds->gl_target, 0,
+                                       x_span->size - x_span->waste,
+                                       local_y,
+                                       x_span->waste,
+                                       inter_h,
+                                       source_gl_format,
+                                       source_gl_type,
+                                       waste_buf) );
+                }
             }
 
           /* same for the bottom-most pixels */
@@ -515,50 +561,59 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
               && local_y < y_span->size - y_span->waste
               && local_y + inter_h >= y_span->size - y_span->waste)
             {
-              const guint8 *src;
-              guint8 *dst;
-              unsigned int wy, wx;
-              unsigned int copy_width;
-
-              src = source_bmp->data
-                + (src_x +  ((int)x_iter.intersect_start)
-                   - dst_x)
-                * bpp
-                + (src_y + y_span->start + y_span->size - y_span->waste
-                   - dst_y - 1)
-                * source_bmp->rowstride;
-
-              dst = waste_buf;
-
-              if (local_x + inter_w >= x_span->size - x_span->waste)
-                copy_width = x_span->size - local_x;
-              else
-                copy_width = inter_w;
-
-              for (wy = 0; wy < y_span->waste; wy++)
-                {
-                  memcpy (dst, src, inter_w * bpp);
-                  dst += inter_w * bpp;
+              int bmp_rowstride = _cogl_bitmap_get_rowstride (source_bmp);
+              guint8 *bmp_data = _cogl_bitmap_map (source_bmp,
+                                                   COGL_BUFFER_ACCESS_READ, 0);
 
-                  for (wx = inter_w; wx < copy_width; wx++)
+              if (bmp_data)
+                {
+                  const guint8 *src;
+                  guint8 *dst;
+                  unsigned int wy, wx;
+                  unsigned int copy_width;
+
+                  src = bmp_data
+                    + (src_x +  ((int)x_iter.intersect_start)
+                       - dst_x)
+                    * bpp
+                    + (src_y + y_span->start + y_span->size - y_span->waste
+                       - dst_y - 1)
+                    * bmp_rowstride;
+
+                  dst = waste_buf;
+
+                  if (local_x + inter_w >= x_span->size - x_span->waste)
+                    copy_width = x_span->size - local_x;
+                  else
+                    copy_width = inter_w;
+
+                  for (wy = 0; wy < y_span->waste; wy++)
                     {
-                      memcpy (dst, dst - bpp, bpp);
-                      dst += bpp;
+                      memcpy (dst, src, inter_w * bpp);
+                      dst += inter_w * bpp;
+
+                      for (wx = inter_w; wx < copy_width; wx++)
+                        {
+                          memcpy (dst, dst - bpp, bpp);
+                          dst += bpp;
+                        }
                     }
-                }
 
-              _cogl_texture_driver_prep_gl_for_pixels_upload (
-                                                          copy_width * bpp,
-                                                          bpp);
+                  _cogl_bitmap_unmap (source_bmp);
 
-              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
-                                   local_x,
-                                   y_span->size - y_span->waste,
-                                   copy_width,
-                                   y_span->waste,
-                                   source_gl_format,
-                                   source_gl_type,
-                                   waste_buf) );
+                  _cogl_texture_driver_prep_gl_for_pixels_upload (
+                                                              copy_width * bpp,
+                                                              bpp);
+
+                  GE( glTexSubImage2D (tex_2ds->gl_target, 0,
+                                       local_x,
+                                       y_span->size - y_span->waste,
+                                       copy_width,
+                                       y_span->waste,
+                                       source_gl_format,
+                                       source_gl_type,
+                                       waste_buf) );
+                }
             }
         }
     }
@@ -914,15 +969,15 @@ _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
 }
 
 static gboolean
-_cogl_texture_2d_sliced_upload_from_data
-                                      (CoglTexture2DSliced *tex_2ds,
-                                       CoglBitmap          *bmp,
-                                       CoglPixelFormat      internal_format)
+_cogl_texture_2d_sliced_init_base (CoglTexture2DSliced *tex_2ds,
+                                   int width,
+                                   int height,
+                                   GLenum gl_intformat,
+                                   GLenum gl_format,
+                                   GLenum gl_type,
+                                   CoglPixelFormat internal_format)
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2ds);
-  GLenum gl_intformat;
-  GLenum gl_format;
-  GLenum gl_type;
 
   tex->vtable = &cogl_texture_2d_sliced_vtable;
 
@@ -939,71 +994,18 @@ _cogl_texture_2d_sliced_upload_from_data
   tex_2ds->min_filter = GL_LINEAR;
   tex_2ds->mag_filter = GL_LINEAR;
 
-  if (bmp->data)
-    {
-      CoglBitmap dst_bmp;
-      gboolean dst_bmp_owner;
-
-      if (!_cogl_texture_prepare_for_upload (bmp,
-                                             internal_format,
-                                             &internal_format,
-                                             &dst_bmp,
-                                             &dst_bmp_owner,
-                                             &gl_intformat,
-                                             &gl_format,
-                                             &gl_type))
-        return FALSE;
-
-      /* Create slices for the given format and size */
-      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
-                                                  dst_bmp.width,
-                                                  dst_bmp.height,
-                                                  gl_intformat,
-                                                  gl_format,
-                                                  gl_type))
-        {
-          if (dst_bmp_owner)
-            g_free (dst_bmp.data);
-
-          return FALSE;
-        }
-
-      if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
-                                                 &dst_bmp,
-                                                 gl_intformat,
-                                                 gl_format,
-                                                 gl_type))
-        {
-          if (dst_bmp_owner)
-            g_free (dst_bmp.data);
-
-          return FALSE;
-        }
-
-      if (dst_bmp_owner)
-        g_free (dst_bmp.data);
-    }
-  else
-    {
-      /* Find closest GL format match */
-      internal_format = _cogl_pixel_format_to_gl (internal_format,
-                                                  &gl_intformat,
-                                                  &gl_format,
-                                                  &gl_type);
-
-      /* Create slices for the given format and size */
-      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
-                                                  bmp->width,
-                                                  bmp->height,
-                                                  gl_intformat,
-                                                  gl_format,
-                                                  gl_type))
-        return FALSE;
-    }
+  /* Create slices for the given format and size */
+  if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
+                                              width,
+                                              height,
+                                              gl_intformat,
+                                              gl_format,
+                                              gl_type))
+    return FALSE;
 
   tex_2ds->gl_format = gl_intformat;
-  tex_2ds->width = bmp->width;
-  tex_2ds->height = bmp->height;
+  tex_2ds->width = width;
+  tex_2ds->height = height;
   tex_2ds->format = internal_format;
 
   return TRUE;
@@ -1016,7 +1018,9 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int     width,
                                        CoglPixelFormat  internal_format)
 {
   CoglTexture2DSliced   *tex_2ds;
-  CoglBitmap             bmp;
+  GLenum                 gl_intformat;
+  GLenum                 gl_format;
+  GLenum                 gl_type;
 
   /* Since no data, we need some internal format */
   if (internal_format == COGL_PIXEL_FORMAT_ANY)
@@ -1025,17 +1029,34 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int     width,
   /* Init texture with empty bitmap */
   tex_2ds = g_new (CoglTexture2DSliced, 1);
 
-  bmp.width = width;
-  bmp.height = height;
-  bmp.data = NULL;
-
   if ((flags & COGL_TEXTURE_NO_SLICING))
     tex_2ds->max_waste = -1;
   else
     tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE;
 
-  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &bmp,
-                                                 internal_format))
+  /* Find closest GL format match */
+  internal_format = _cogl_pixel_format_to_gl (internal_format,
+                                              &gl_intformat,
+                                              &gl_format,
+                                              &gl_type);
+
+  if (!_cogl_texture_2d_sliced_init_base (tex_2ds,
+                                          width, height,
+                                          gl_intformat,
+                                          gl_format,
+                                          gl_type,
+                                          internal_format))
+    {
+      _cogl_texture_2d_sliced_free (tex_2ds);
+      return COGL_INVALID_HANDLE;
+    }
+
+  if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
+                                              width,
+                                              height,
+                                              gl_intformat,
+                                              gl_format,
+                                              gl_type))
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
       return COGL_INVALID_HANDLE;
@@ -1047,14 +1068,21 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int     width,
 }
 
 CoglHandle
-_cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap      *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat  internal_format)
 {
-  CoglTexture2DSliced   *tex_2ds;
-  CoglBitmap            *bmp = (CoglBitmap *)bmp_handle;
+  CoglTexture2DSliced *tex_2ds;
+  CoglBitmap          *dst_bmp;
+  GLenum               gl_intformat;
+  GLenum               gl_format;
+  GLenum               gl_type;
+  int                  width, height;
+
+  g_return_val_if_fail (cogl_is_bitmap (bmp), COGL_INVALID_HANDLE);
 
-  g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
+  width = _cogl_bitmap_get_width (bmp);
+  height = _cogl_bitmap_get_height (bmp);
 
   /* Create new texture and fill with loaded data */
   tex_2ds = g_new0 (CoglTexture2DSliced, 1);
@@ -1072,16 +1100,50 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
    * CoglHandle is returned, it should also be destroyed
    * with cogl_handle_unref at some point! */
 
-  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, bmp,
-                                                 internal_format))
+  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                              internal_format,
+                                              &internal_format,
+                                              &gl_intformat,
+                                              &gl_format,
+                                              &gl_type);
+  if (dst_bmp == COGL_INVALID_HANDLE)
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
       return COGL_INVALID_HANDLE;
     }
 
+  if (!_cogl_texture_2d_sliced_init_base (tex_2ds,
+                                          width, height,
+                                          gl_intformat,
+                                          gl_format,
+                                          gl_type,
+                                          internal_format))
+    goto error;
+
+  if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
+                                              width, height,
+                                              gl_intformat,
+                                              gl_format,
+                                              gl_type))
+    goto error;
+
+  if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
+                                             dst_bmp,
+                                             gl_intformat,
+                                             gl_format,
+                                             gl_type))
+    goto error;
+
+  cogl_object_unref (dst_bmp);
+
   tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
 
   return _cogl_texture_2d_sliced_handle_new (tex_2ds);
+
+ error:
+  cogl_object_unref (dst_bmp);
+  _cogl_texture_2d_sliced_free (tex_2ds);
+  return COGL_INVALID_HANDLE;
 }
 
 CoglHandle
@@ -1467,7 +1529,7 @@ _cogl_texture_2d_sliced_set_region (CoglTexture    *tex,
   GLenum               gl_format;
   GLenum               gl_type;
 
-  _cogl_pixel_format_to_gl (bmp->format,
+  _cogl_pixel_format_to_gl (_cogl_bitmap_get_format (bmp),
                             NULL, /* internal format */
                             &gl_format,
                             &gl_type);
@@ -1491,14 +1553,15 @@ _cogl_texture_2d_sliced_download_from_gl (
                                       GLuint               target_gl_format,
                                       GLuint               target_gl_type)
 {
-  CoglSpan  *x_span;
-  CoglSpan  *y_span;
-  GLuint     gl_handle;
-  int        bpp;
-  int        x, y;
-  CoglBitmap slice_bmp;
+  CoglSpan   *x_span;
+  CoglSpan   *y_span;
+  GLuint      gl_handle;
+  int         bpp;
+  int         x, y;
+  CoglBitmap *slice_bmp;
+  CoglPixelFormat target_format = _cogl_bitmap_get_format (target_bmp);
 
-  bpp = _cogl_get_format_bpp (target_bmp->format);
+  bpp = _cogl_get_format_bpp (target_format);
 
   /* Iterate vertical slices */
   for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
@@ -1520,18 +1583,21 @@ _cogl_texture_2d_sliced_download_from_gl (
 
          if (y_span->waste != 0 || x_span->waste != 0)
            {
+              int rowstride = x_span->size * bpp;
+              guint8 *data = g_malloc (rowstride * y_span->size);
+
              /* Setup temp bitmap for slice subregion */
-             slice_bmp.format = target_bmp->format;
-             slice_bmp.width  = x_span->size;
-             slice_bmp.height = y_span->size;
-             slice_bmp.rowstride = bpp * slice_bmp.width;
-             slice_bmp.data = g_malloc (slice_bmp.rowstride *
-                                        slice_bmp.height);
+              slice_bmp = _cogl_bitmap_new_from_data (data,
+                                                      target_format,
+                                                      x_span->size,
+                                                      y_span->size,
+                                                      rowstride,
+                                                      (CoglBitmapDestroyNotify)
+                                                      g_free,
+                                                      NULL);
 
              /* Setup gl alignment to 0,0 top-left corner */
-             _cogl_texture_driver_prep_gl_for_pixels_download (
-                                                          slice_bmp.rowstride,
-                                                          bpp);
+              _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp);
 
              /* Download slice image data into temp bmp */
               _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
@@ -1541,15 +1607,15 @@ _cogl_texture_2d_sliced_download_from_gl (
               if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
                                                           target_gl_format,
                                                           target_gl_type,
-                                                          slice_bmp.data))
+                                                          data))
                 {
                   /* Free temp bitmap */
-                  g_free (slice_bmp.data);
+                  cogl_object_unref (slice_bmp);
                   return FALSE;
                 }
 
              /* Copy portion of slice from temp to target bmp */
-             _cogl_bitmap_copy_subregion (&slice_bmp,
+             _cogl_bitmap_copy_subregion (slice_bmp,
                                           target_bmp,
                                           0, 0,
                                           x_span->start,
@@ -1557,30 +1623,39 @@ _cogl_texture_2d_sliced_download_from_gl (
                                           x_span->size - x_span->waste,
                                           y_span->size - y_span->waste);
              /* Free temp bitmap */
-             g_free (slice_bmp.data);
+              cogl_object_unref (slice_bmp);
            }
          else
            {
-             GLvoid *dst = target_bmp->data
-                           + x_span->start * bpp
-                           + y_span->start * target_bmp->rowstride;
+              guint8 *data;
+              GLvoid *dst;
+              gboolean ret;
+              int rowstride = _cogl_bitmap_get_rowstride (target_bmp);
+
+              data = _cogl_bitmap_map (target_bmp,
+                                       COGL_BUFFER_ACCESS_WRITE,
+                                       0);
+              if (data == NULL)
+                return FALSE;
 
-             _cogl_texture_driver_prep_gl_for_pixels_download (
-                                                        target_bmp->rowstride,
-                                                        bpp);
+              dst = data + x_span->start * bpp + y_span->start * rowstride;
+
+              _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp);
 
              /* Download slice image data */
               _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
                                                gl_handle,
                                                tex_2ds->is_foreign);
 
-              if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
-                                                          target_gl_format,
-                                                          target_gl_type,
-                                                          dst))
-                {
-                  return FALSE;
-                }
+              ret = _cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
+                                                           target_gl_format,
+                                                           target_gl_type,
+                                                           dst);
+
+              _cogl_bitmap_unmap (target_bmp);
+
+              if (!ret)
+                return ret;
            }
        }
     }
@@ -1588,7 +1663,7 @@ _cogl_texture_2d_sliced_download_from_gl (
   return TRUE;
 }
 
-static int
+static gboolean
 _cogl_texture_2d_sliced_get_data (CoglTexture     *tex,
                                   CoglPixelFormat  format,
                                   unsigned int     rowstride,
@@ -1598,7 +1673,8 @@ _cogl_texture_2d_sliced_get_data (CoglTexture     *tex,
   int             bpp;
   GLenum          gl_format;
   GLenum          gl_type;
-  CoglBitmap      target_bmp;
+  CoglBitmap     *target_bmp;
+  gboolean        ret;
 
   bpp = _cogl_get_format_bpp (format);
 
@@ -1607,16 +1683,23 @@ _cogl_texture_2d_sliced_get_data (CoglTexture     *tex,
                             &gl_format,
                             &gl_type);
 
-  target_bmp.width = tex_2ds->width;
-  target_bmp.height = tex_2ds->height;
-  target_bmp.format = format;
-  target_bmp.rowstride = rowstride;
-  target_bmp.data = data;
+  target_bmp = _cogl_bitmap_new_from_data (data,
+                                           format,
+                                           tex_2ds->width,
+                                           tex_2ds->height,
+                                           rowstride,
+                                           NULL, /* destroy_fn */
+                                           NULL /* destroy_fn_data */);
 
   /* Retrieve data from slices */
-  return _cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp,
-                                                   gl_format,
-                                                   gl_type);
+  ret = _cogl_texture_2d_sliced_download_from_gl (tex_2ds,
+                                                  target_bmp,
+                                                  gl_format,
+                                                  gl_type);
+
+  cogl_object_unref (target_bmp);
+
+  return ret;
 }
 
 static CoglPixelFormat
index d7b95ff..173d407 100644 (file)
@@ -254,61 +254,67 @@ _cogl_texture_2d_new_with_size (unsigned int     width,
 }
 
 CoglHandle
-_cogl_texture_2d_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format)
 {
   CoglTexture2D *tex_2d;
-  CoglBitmap    *bmp = (CoglBitmap *)bmp_handle;
-  CoglBitmap     dst_bmp;
-  gboolean       dst_bmp_owner;
+  CoglBitmap    *dst_bmp;
   GLenum         gl_intformat;
   GLenum         gl_format;
   GLenum         gl_type;
+  guint8        *data;
 
-  g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
+  g_return_val_if_fail (bmp != NULL, COGL_INVALID_HANDLE);
 
-  internal_format = _cogl_texture_determine_internal_format (bmp->format,
-                                                             internal_format);
+  internal_format =
+    _cogl_texture_determine_internal_format (_cogl_bitmap_get_format (bmp),
+                                             internal_format);
 
-  if (!_cogl_texture_2d_can_create (bmp->width, bmp->height, internal_format))
+  if (!_cogl_texture_2d_can_create (_cogl_bitmap_get_width (bmp),
+                                    _cogl_bitmap_get_height (bmp),
+                                    internal_format))
     return COGL_INVALID_HANDLE;
 
-  if (!_cogl_texture_prepare_for_upload (bmp,
-                                         internal_format,
-                                         &internal_format,
-                                         &dst_bmp,
-                                         &dst_bmp_owner,
-                                         &gl_intformat,
-                                         &gl_format,
-                                         &gl_type))
+  if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                                   internal_format,
+                                                   &internal_format,
+                                                   &gl_intformat,
+                                                   &gl_format,
+                                                   &gl_type)) == NULL)
     return COGL_INVALID_HANDLE;
 
-  tex_2d = _cogl_texture_2d_create_base (bmp->width,
-                                         bmp->height,
+  tex_2d = _cogl_texture_2d_create_base (_cogl_bitmap_get_width (bmp),
+                                         _cogl_bitmap_get_height (bmp),
                                          flags,
                                          internal_format);
 
   /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
      supported we can fallback to using GL_GENERATE_MIPMAP */
-  tex_2d->first_pixel.gl_format = gl_format;
-  tex_2d->first_pixel.gl_type = gl_type;
-  memcpy (tex_2d->first_pixel.data, dst_bmp.data,
-          _cogl_get_format_bpp (dst_bmp.format));
+  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
+      (data = _cogl_bitmap_map (dst_bmp,
+                                COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      tex_2d->first_pixel.gl_format = gl_format;
+      tex_2d->first_pixel.gl_type = gl_type;
+      memcpy (tex_2d->first_pixel.data, data,
+              _cogl_get_format_bpp (_cogl_bitmap_get_format (dst_bmp)));
+
+      _cogl_bitmap_unmap (dst_bmp);
+    }
 
   _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
   _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D,
                                      tex_2d->gl_texture,
                                      FALSE,
-                                     &dst_bmp,
+                                     dst_bmp,
                                      gl_intformat,
                                      gl_format,
                                      gl_type);
 
   tex_2d->gl_format = gl_intformat;
 
-  if (dst_bmp_owner)
-    g_free (dst_bmp.data);
+  cogl_object_unref (dst_bmp);
 
   return _cogl_texture_2d_handle_new (tex_2d);
 }
@@ -463,21 +469,27 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
   GLenum         gl_format;
   GLenum         gl_type;
+  guint8        *data;
 
-  _cogl_pixel_format_to_gl (bmp->format,
+  _cogl_pixel_format_to_gl (_cogl_bitmap_get_format (bmp),
                             NULL, /* internal format */
                             &gl_format,
                             &gl_type);
 
   /* If this touches the first pixel then we'll update our copy */
-  if (dst_x == 0 && dst_y == 0)
+  if (dst_x == 0 && dst_y == 0 &&
+      !cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
+      (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
     {
-      CoglPixelFormat bpp = _cogl_get_format_bpp (bmp->format);
+      CoglPixelFormat bpp =
+        _cogl_get_format_bpp (_cogl_bitmap_get_format (bmp));
       tex_2d->first_pixel.gl_format = gl_format;
       tex_2d->first_pixel.gl_type = gl_type;
       memcpy (tex_2d->first_pixel.data,
-              bmp->data + bmp->rowstride * src_y + bpp * src_x,
+              data + _cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
               bpp);
+
+      _cogl_bitmap_unmap (bmp);
     }
 
   /* Send data to GL */
index bb9e5ba..e3a0808 100644 (file)
@@ -88,7 +88,7 @@ _cogl_handle_texture_3d_get_type (void);
  *   there was an error.
  */
 CoglHandle
-_cogl_texture_3d_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_3d_new_from_bitmap (CoglBitmap      *bmp,
                                   unsigned int     height,
                                   unsigned int     depth,
                                   CoglTextureFlags flags,
index ff5a96e..b684fb3 100644 (file)
@@ -303,54 +303,65 @@ cogl_texture_3d_new_with_size (unsigned int     width,
 }
 
 CoglHandle
-_cogl_texture_3d_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_3d_new_from_bitmap (CoglBitmap      *bmp,
                                   unsigned int     height,
                                   unsigned int     depth,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format,
                                   GError         **error)
 {
-  CoglTexture3D *tex_3d;
-  CoglBitmap    *bmp = (CoglBitmap *) bmp_handle;
-  CoglBitmap     dst_bmp;
-  gboolean       dst_bmp_owner;
-  GLenum         gl_intformat;
-  GLenum         gl_format;
-  GLenum         gl_type;
+  CoglTexture3D   *tex_3d;
+  CoglBitmap      *dst_bmp;
+  CoglPixelFormat  bmp_format;
+  unsigned int     bmp_width;
+  GLenum           gl_intformat;
+  GLenum           gl_format;
+  GLenum           gl_type;
+  guint8          *data;
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
-  internal_format = _cogl_texture_determine_internal_format (bmp->format,
+  bmp_width = _cogl_bitmap_get_width (bmp);
+  bmp_format = _cogl_bitmap_get_format (bmp);
+
+  internal_format = _cogl_texture_determine_internal_format (bmp_format,
                                                              internal_format);
 
-  if (!_cogl_texture_3d_can_create (bmp->width, height, depth,
+  if (!_cogl_texture_3d_can_create (bmp_width, height, depth,
                                     flags, internal_format,
                                     error))
     return COGL_INVALID_HANDLE;
 
-  if (!_cogl_texture_prepare_for_upload (bmp,
-                                         internal_format,
-                                         &internal_format,
-                                         &dst_bmp,
-                                         &dst_bmp_owner,
-                                         &gl_intformat,
-                                         &gl_format,
-                                         &gl_type))
+  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                              internal_format,
+                                              &internal_format,
+                                              &gl_intformat,
+                                              &gl_format,
+                                              &gl_type);
+
+  if (dst_bmp == NULL)
     {
       g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED,
                    "Bitmap conversion failed");
       return COGL_INVALID_HANDLE;
     }
 
-  tex_3d = _cogl_texture_3d_create_base (dst_bmp.width, height, depth,
+  tex_3d = _cogl_texture_3d_create_base (bmp_width, height, depth,
                                          flags, internal_format);
 
   /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
      supported we can fallback to using GL_GENERATE_MIPMAP */
-  tex_3d->first_pixel.gl_format = gl_format;
-  tex_3d->first_pixel.gl_type = gl_type;
-  memcpy (tex_3d->first_pixel.data, dst_bmp.data,
-          _cogl_get_format_bpp (dst_bmp.format));
+  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
+      (data = _cogl_bitmap_map (dst_bmp,
+                                COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      tex_3d->first_pixel.gl_format = gl_format;
+      tex_3d->first_pixel.gl_type = gl_type;
+      memcpy (tex_3d->first_pixel.data, data,
+              _cogl_get_format_bpp (_cogl_bitmap_get_format (dst_bmp)));
+
+      _cogl_bitmap_unmap (dst_bmp);
+    }
 
   _cogl_texture_driver_gen (GL_TEXTURE_3D, 1, &tex_3d->gl_texture);
 
@@ -359,15 +370,14 @@ _cogl_texture_3d_new_from_bitmap (CoglHandle       bmp_handle,
                                         FALSE, /* is_foreign */
                                         height,
                                         depth,
-                                        &dst_bmp,
+                                        dst_bmp,
                                         gl_intformat,
                                         gl_format,
                                         gl_type);
 
   tex_3d->gl_format = gl_intformat;
 
-  if (dst_bmp_owner)
-    g_free (dst_bmp.data);
+  cogl_object_unref (dst_bmp);
 
   return _cogl_texture_3d_handle_new (tex_3d);
 }
@@ -384,8 +394,7 @@ cogl_texture_3d_new_from_data (unsigned int      width,
                                const guint8     *data,
                                GError          **error)
 {
-  CoglBitmap bitmap;
-  gboolean bitmap_owned = FALSE;
+  CoglBitmap *bitmap;
   CoglHandle ret;
 
   /* These are considered a programmer errors so we won't set a
@@ -414,42 +423,42 @@ cogl_texture_3d_new_from_data (unsigned int      width,
   if (image_stride % rowstride != 0)
     {
       int z, y;
+      int bmp_rowstride = _cogl_get_format_bpp (format) * width;
+      guint8 *bmp_data = g_malloc (bmp_rowstride * height * depth);
 
-      bitmap.width = width;
-      bitmap.height = depth * height;
-      bitmap.rowstride = _cogl_get_format_bpp (format) * width;
-      bitmap.data = g_malloc (bitmap.rowstride * height * depth);
-      bitmap.format = format;
+      bitmap = _cogl_bitmap_new_from_data (bmp_data,
+                                           format,
+                                           width,
+                                           depth * height,
+                                           bmp_rowstride,
+                                           (CoglBitmapDestroyNotify) g_free,
+                                           NULL /* destroy_fn_data */);
 
       /* Copy all of the images in */
       for (z = 0; z < depth; z++)
         for (y = 0; y < height; y++)
-          memcpy (bitmap.data + (z * bitmap.rowstride * height +
-                                 bitmap.rowstride * y),
+          memcpy (bmp_data + (z * bmp_rowstride * height +
+                              bmp_rowstride * y),
                   data + z * image_stride + rowstride * y,
-                  bitmap.rowstride);
-
-      bitmap_owned = TRUE;
+                  bmp_rowstride);
     }
   else
-    {
-      /* Wrap the data into a bitmap */
-      bitmap.width = width;
-      bitmap.height = image_stride / rowstride * depth;
-      bitmap.data = (guint8 *) data;
-      bitmap.format = format;
-      bitmap.rowstride = rowstride;
-    }
-
-  ret = _cogl_texture_3d_new_from_bitmap (&bitmap,
+    bitmap = _cogl_bitmap_new_from_data ((guint8 *) data,
+                                         format,
+                                         width,
+                                         image_stride / rowstride * depth,
+                                         rowstride,
+                                         NULL, /* destroy_fn */
+                                         NULL /* destroy_fn_data */);
+
+  ret = _cogl_texture_3d_new_from_bitmap (bitmap,
                                           height,
                                           depth,
                                           flags,
                                           internal_format,
                                           error);
 
-  if (bitmap_owned)
-    g_free (bitmap.data);
+  cogl_object_unref (bitmap);
 
   return ret;
 }
index 454cb84..80b4ade 100644 (file)
@@ -240,12 +240,10 @@ _cogl_texture_determine_internal_format (CoglPixelFormat src_format,
    be set to TRUE. Otherwise dst_bmp will be set to a shallow copy of
    src_bmp. The GLenums needed for uploading are returned */
 
-gboolean
+CoglBitmap *
 _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
                                   CoglPixelFormat  dst_format,
                                   CoglPixelFormat *dst_format_out,
-                                  CoglBitmap      *dst_bmp,
-                                  gboolean        *copied_bitmap,
                                   GLenum          *out_glintformat,
                                   GLenum          *out_glformat,
                                   GLenum          *out_gltype);
index 0a3e446..6f5313c 100644 (file)
@@ -61,7 +61,7 @@ _cogl_texture_rectangle_new_with_size (unsigned int     width,
                                        CoglPixelFormat  internal_format);
 
 CoglHandle
-_cogl_texture_rectangle_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_rectangle_new_from_bitmap (CoglBitmap      *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat  internal_format);
 
index 9ca3c4c..57c686c 100644 (file)
@@ -278,39 +278,39 @@ _cogl_texture_rectangle_new_with_size (unsigned int     width,
 }
 
 CoglHandle
-_cogl_texture_rectangle_new_from_bitmap (CoglHandle       bmp_handle,
+_cogl_texture_rectangle_new_from_bitmap (CoglBitmap      *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat  internal_format)
 {
   CoglTextureRectangle *tex_rect;
-  CoglBitmap           *bmp = (CoglBitmap *)bmp_handle;
-  CoglBitmap            dst_bmp;
-  gboolean              dst_bmp_owner;
+  CoglBitmap           *dst_bmp;
   GLenum                gl_intformat;
   GLenum                gl_format;
   GLenum                gl_type;
 
-  g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
+  g_return_val_if_fail (cogl_is_bitmap (bmp), COGL_INVALID_HANDLE);
 
-  internal_format = _cogl_texture_determine_internal_format (bmp->format,
-                                                             internal_format);
+  internal_format =
+    _cogl_texture_determine_internal_format (_cogl_bitmap_get_format (bmp),
+                                             internal_format);
 
-  if (!_cogl_texture_rectangle_can_create (bmp->width, bmp->height,
+  if (!_cogl_texture_rectangle_can_create (_cogl_bitmap_get_width (bmp),
+                                           _cogl_bitmap_get_height (bmp),
                                            internal_format))
     return COGL_INVALID_HANDLE;
 
-  if (!_cogl_texture_prepare_for_upload (bmp,
-                                         internal_format,
-                                         &internal_format,
-                                         &dst_bmp,
-                                         &dst_bmp_owner,
-                                         &gl_intformat,
-                                         &gl_format,
-                                         &gl_type))
+  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                              internal_format,
+                                              &internal_format,
+                                              &gl_intformat,
+                                              &gl_format,
+                                              &gl_type);
+
+  if (dst_bmp == NULL)
     return COGL_INVALID_HANDLE;
 
-  tex_rect = _cogl_texture_rectangle_create_base (bmp->width,
-                                                  bmp->height,
+  tex_rect = _cogl_texture_rectangle_create_base (_cogl_bitmap_get_width (bmp),
+                                                  _cogl_bitmap_get_height (bmp),
                                                   flags,
                                                   internal_format);
 
@@ -318,15 +318,14 @@ _cogl_texture_rectangle_new_from_bitmap (CoglHandle       bmp_handle,
   _cogl_texture_driver_upload_to_gl (GL_TEXTURE_RECTANGLE_ARB,
                                      tex_rect->gl_texture,
                                      FALSE,
-                                     &dst_bmp,
+                                     dst_bmp,
                                      gl_intformat,
                                      gl_format,
                                      gl_type);
 
   tex_rect->gl_format = gl_intformat;
 
-  if (dst_bmp_owner)
-    g_free (dst_bmp.data);
+  cogl_object_unref (dst_bmp);
 
   return _cogl_texture_rectangle_handle_new (tex_rect);
 }
@@ -453,7 +452,7 @@ _cogl_texture_rectangle_set_region (CoglTexture    *tex,
   GLenum                gl_format;
   GLenum                gl_type;
 
-  _cogl_pixel_format_to_gl (bmp->format,
+  _cogl_pixel_format_to_gl (_cogl_bitmap_get_format (bmp),
                             NULL, /* internal format */
                             &gl_format,
                             &gl_type);
index 519c29d..1a633b2 100644 (file)
@@ -152,21 +152,19 @@ _cogl_texture_determine_internal_format (CoglPixelFormat src_format,
     return dst_format;
 }
 
-gboolean
+CoglBitmap *
 _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
                                   CoglPixelFormat  dst_format,
                                   CoglPixelFormat *dst_format_out,
-                                  CoglBitmap      *dst_bmp,
-                                  gboolean        *copied_bitmap,
                                   GLenum          *out_glintformat,
                                   GLenum          *out_glformat,
                                   GLenum          *out_gltype)
 {
-  dst_format = _cogl_texture_determine_internal_format (src_bmp->format,
-                                                        dst_format);
+  CoglPixelFormat src_format = _cogl_bitmap_get_format (src_bmp);
+  CoglBitmap *dst_bmp;
 
-  *copied_bitmap = FALSE;
-  *dst_bmp = *src_bmp;
+  dst_format = _cogl_texture_determine_internal_format (src_format,
+                                                        dst_format);
 
   /* OpenGL supports specifying a different format for the internal
      format when uploading texture data. We should use this to convert
@@ -180,26 +178,46 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
 
   /* If the source format does not have the same premult flag as the
      dst format then we need to copy and convert it */
-  if (_cogl_texture_needs_premult_conversion (src_bmp->format,
+  if (_cogl_texture_needs_premult_conversion (src_format,
                                               dst_format))
     {
-      dst_bmp->data = g_memdup (dst_bmp->data,
-                                dst_bmp->height * dst_bmp->rowstride);
-      *copied_bitmap = TRUE;
+      guint8 *src_data;
+      guint8 *dst_data;
+
+      if ((src_data = _cogl_bitmap_map (src_bmp,
+                                        COGL_BUFFER_ACCESS_READ, 0)) == NULL)
+        return NULL;
+
+      dst_data = g_memdup (src_data,
+                           _cogl_bitmap_get_height (src_bmp) *
+                           _cogl_bitmap_get_rowstride (src_bmp));
+
+      _cogl_bitmap_unmap (src_bmp);
+
+      dst_bmp =
+        _cogl_bitmap_new_from_data (dst_data,
+                                    src_format,
+                                    _cogl_bitmap_get_width (src_bmp),
+                                    _cogl_bitmap_get_height (src_bmp),
+                                    _cogl_bitmap_get_rowstride (src_bmp),
+                                    (CoglBitmapDestroyNotify) g_free,
+                                    NULL);
 
       if (!_cogl_bitmap_convert_premult_status (dst_bmp,
-                                                src_bmp->format ^
+                                                src_format ^
                                                 COGL_PREMULT_BIT))
         {
-          g_free (dst_bmp->data);
-          return FALSE;
+          cogl_object_unref (dst_bmp);
+          return NULL;
         }
     }
+  else
+    dst_bmp = cogl_object_ref (src_bmp);
 
   /* Use the source format from the src bitmap type and the internal
      format from the dst format type so that GL can do the
      conversion */
-  _cogl_pixel_format_to_gl (src_bmp->format,
+  _cogl_pixel_format_to_gl (src_format,
                             NULL, /* internal format */
                             out_glformat,
                             out_gltype);
@@ -212,28 +230,23 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
   {
     CoglPixelFormat closest_format;
 
-    closest_format = _cogl_pixel_format_to_gl (dst_bmp->format,
+    closest_format = _cogl_pixel_format_to_gl (dst_format,
                                                out_glintformat,
                                                out_glformat,
                                                out_gltype);
 
-
-    if (closest_format != src_bmp->format)
-      {
-        if (!_cogl_bitmap_convert_format_and_premult (src_bmp,
-                                                      dst_bmp,
-                                                      closest_format))
-          return FALSE;
-
-        *copied_bitmap = TRUE;
-      }
+    if (closest_format != src_format)
+      dst_bmp = _cogl_bitmap_convert_format_and_premult (src_bmp,
+                                                         closest_format);
+    else
+      dst_bmp = cogl_object_ref (src_bmp);
   }
 #endif /* HAVE_COGL_GL */
 
   if (dst_format_out)
     *dst_format_out = dst_format;
 
-  return TRUE;
+  return dst_bmp;
 }
 
 void
@@ -402,7 +415,8 @@ cogl_texture_new_from_data (unsigned int      width,
                            unsigned int      rowstride,
                            const guint8     *data)
 {
-  CoglBitmap bitmap;
+  CoglBitmap *bmp;
+  CoglHandle tex;
 
   if (format == COGL_PIXEL_FORMAT_ANY)
     return COGL_INVALID_HANDLE;
@@ -415,13 +429,18 @@ cogl_texture_new_from_data (unsigned int      width,
     rowstride = width * _cogl_get_format_bpp (format);
 
   /* Wrap the data into a bitmap */
-  bitmap.width = width;
-  bitmap.height = height;
-  bitmap.data = (guint8 *) data;
-  bitmap.format = format;
-  bitmap.rowstride = rowstride;
+  bmp = _cogl_bitmap_new_from_data ((guint8 *) data,
+                                    format,
+                                    width,
+                                    height,
+                                    rowstride,
+                                    NULL, NULL);
 
-  return cogl_texture_new_from_bitmap (&bitmap, flags, internal_format);
+  tex = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
+
+  cogl_object_unref (bmp);
+
+  return tex;
 }
 
 CoglHandle
@@ -455,29 +474,29 @@ cogl_texture_new_from_file (const char        *filename,
                             CoglPixelFormat    internal_format,
                             GError           **error)
 {
-  CoglHandle bmp_handle;
   CoglBitmap *bmp;
   CoglHandle handle = COGL_INVALID_HANDLE;
+  CoglPixelFormat src_format;
 
   g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
 
-  bmp_handle = cogl_bitmap_new_from_file (filename, error);
-  if (bmp_handle == COGL_INVALID_HANDLE)
+  bmp = cogl_bitmap_new_from_file (filename, error);
+  if (bmp == NULL)
     return COGL_INVALID_HANDLE;
 
-  bmp = (CoglBitmap *) bmp_handle;
+  src_format = _cogl_bitmap_get_format (bmp);
 
   /* We know that the bitmap data is solely owned by this function so
      we can do the premult conversion in place. This avoids having to
      copy the bitmap which will otherwise happen in
      _cogl_texture_prepare_for_upload */
-  internal_format = _cogl_texture_determine_internal_format (bmp->format,
-                                                             internal_format);
-  if (!_cogl_texture_needs_premult_conversion (bmp->format, internal_format) ||
-      _cogl_bitmap_convert_premult_status (bmp, bmp->format ^ COGL_PREMULT_BIT))
+  internal_format =
+    _cogl_texture_determine_internal_format (src_format, internal_format);
+  if (!_cogl_texture_needs_premult_conversion (src_format, internal_format) ||
+      _cogl_bitmap_convert_premult_status (bmp, src_format ^ COGL_PREMULT_BIT))
     handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
 
-  cogl_handle_unref (bmp);
+  cogl_object_unref (bmp);
 
   return handle;
 }
@@ -572,19 +591,21 @@ cogl_texture_new_from_buffer_EXP (CoglHandle          buffer,
 #if !defined (COGL_HAS_GLES)
   if (cogl_features_available (COGL_FEATURE_PBOS))
     {
-      CoglBitmap bitmap;
+      CoglBitmap *bmp;
 
       /* Wrap the data into a bitmap */
-      bitmap.width = width;
-      bitmap.height = height;
-      bitmap.data = GUINT_TO_POINTER (offset);
-      bitmap.format = format;
-      bitmap.rowstride = rowstride;
+      bmp = _cogl_bitmap_new_from_data (GUINT_TO_POINTER (offset),
+                                        format,
+                                        width, height,
+                                        rowstride,
+                                        NULL, NULL);
 
       _cogl_buffer_bind (cogl_buffer,
                          COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK);
-      texture =  cogl_texture_new_from_bitmap (&bitmap, flags, internal_format);
+      texture =  cogl_texture_new_from_bitmap (bmp, flags, internal_format);
       _cogl_buffer_unbind (cogl_buffer);
+
+      cogl_object_unref (bmp);
     }
   else
 #endif
@@ -823,8 +844,6 @@ _cogl_texture_set_region_from_bitmap (CoglHandle    handle,
                                       CoglBitmap   *bmp)
 {
   CoglTexture *tex = COGL_TEXTURE (handle);
-  CoglBitmap   tmp_bmp;
-  gboolean     tmp_bmp_owner = FALSE;
   GLenum       closest_gl_format;
   GLenum       closest_gl_type;
   gboolean     ret;
@@ -835,24 +854,20 @@ _cogl_texture_set_region_from_bitmap (CoglHandle    handle,
 
   /* Prepare the bitmap so that it will do the premultiplication
      conversion */
-  _cogl_texture_prepare_for_upload (bmp,
-                                    cogl_texture_get_format (handle),
-                                    NULL,
-                                    &tmp_bmp,
-                                    &tmp_bmp_owner,
-                                    NULL,
-                                    &closest_gl_format,
-                                    &closest_gl_type);
+  bmp = _cogl_texture_prepare_for_upload (bmp,
+                                          cogl_texture_get_format (handle),
+                                          NULL,
+                                          NULL,
+                                          &closest_gl_format,
+                                          &closest_gl_type);
 
   ret = tex->vtable->set_region (handle,
                                  src_x, src_y,
                                  dst_x, dst_y,
                                  dst_width, dst_height,
-                                 &tmp_bmp);
+                                 bmp);
 
-  /* Free data if owner */
-  if (tmp_bmp_owner)
-    g_free (tmp_bmp.data);
+  cogl_object_unref (bmp);
 
   return ret;
 }
@@ -871,28 +886,35 @@ cogl_texture_set_region (CoglHandle       handle,
                         unsigned int     rowstride,
                         const guint8    *data)
 {
-  int              bpp;
-  CoglBitmap       source_bmp;
+  CoglBitmap *source_bmp;
+  gboolean    ret;
 
   /* Check for valid format */
   if (format == COGL_PIXEL_FORMAT_ANY)
     return FALSE;
 
-  /* Init source bitmap */
-  source_bmp.width = width;
-  source_bmp.height = height;
-  source_bmp.format = format;
-  source_bmp.data = (guint8 *) data;
-
   /* Rowstride from width if none specified */
-  bpp = _cogl_get_format_bpp (format);
-  source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
+  if (rowstride == 0)
+    rowstride = _cogl_get_format_bpp (format) * width;
 
-  return _cogl_texture_set_region_from_bitmap (handle,
-                                               src_x, src_y,
-                                               dst_x, dst_y,
-                                               dst_width, dst_height,
-                                               &source_bmp);
+  /* Init source bitmap */
+  source_bmp = _cogl_bitmap_new_from_data ((guint8 *) data,
+                                           format,
+                                           width,
+                                           height,
+                                           rowstride,
+                                           NULL, /* destroy_fn */
+                                           NULL); /* destroy_fn_data */
+
+  ret = _cogl_texture_set_region_from_bitmap (handle,
+                                              src_x, src_y,
+                                              dst_x, dst_y,
+                                              dst_width, dst_height,
+                                              source_bmp);
+
+  cogl_object_unref (source_bmp);
+
+  return ret;
 }
 
 /* Reads back the contents of a texture by rendering it to the framebuffer
@@ -919,7 +941,7 @@ do_texture_draw_and_read (CoglHandle   handle,
   float       tx1, ty1;
   float       tx2, ty2;
   int         bw,  bh;
-  CoglBitmap  rect_bmp;
+  CoglBitmap  *rect_bmp;
   unsigned int  tex_width, tex_height;
 
   bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
@@ -947,10 +969,19 @@ do_texture_draw_and_read (CoglHandle   handle,
       /* Walk X axis until whole bitmap width consumed */
       for (bw = tex_width; bw > 0; bw-=viewport[2])
         {
+          int width;
+          int height;
+          int rowstride;
+          guint8 *data;
+
           /* Rectangle X coords */
           rx1 = rx2;
           rx2 += (bw < viewport[2]) ? bw : viewport[2];
 
+          width = rx2 - rx1;
+          height = ry2 - ry1;
+          rowstride = width * bpp;
+
           /* Normalized texture X coords */
           tx1 = tx2;
           tx2 = (rx2 / (float) tex_width);
@@ -962,31 +993,35 @@ do_texture_draw_and_read (CoglHandle   handle,
                                               tx1, ty1,
                                               tx2, ty2);
 
+          data = g_malloc (height * rowstride);
+
           /* Read into a temporary bitmap */
-          rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
-          rect_bmp.width = rx2 - rx1;
-          rect_bmp.height = ry2 - ry1;
-          rect_bmp.rowstride = bpp * rect_bmp.width;
-          rect_bmp.data = g_malloc (rect_bmp.rowstride *
-                                    rect_bmp.height);
+          rect_bmp =
+            _cogl_bitmap_new_from_data (data,
+                                        COGL_PIXEL_FORMAT_RGBA_8888,
+                                        width,
+                                        height,
+                                        rowstride,
+                                        (CoglBitmapDestroyNotify) g_free,
+                                        NULL);
 
           cogl_read_pixels (viewport[0], viewport[1],
-                            rect_bmp.width,
-                            rect_bmp.height,
+                            width,
+                            height,
                             COGL_READ_PIXELS_COLOR_BUFFER,
                             COGL_PIXEL_FORMAT_RGBA_8888_PRE,
-                            rect_bmp.data);
+                            data);
 
           /* Copy to target bitmap */
-          _cogl_bitmap_copy_subregion (&rect_bmp,
+          _cogl_bitmap_copy_subregion (rect_bmp,
                                        target_bmp,
                                        0,0,
                                        rx1,ry1,
-                                       rect_bmp.width,
-                                       rect_bmp.height);
+                                       width,
+                                       height);
 
           /* Free temp bitmap */
-          g_free (rect_bmp.data);
+          cogl_object_unref (rect_bmp);
         }
     }
 }
@@ -1006,10 +1041,13 @@ _cogl_texture_draw_and_read (CoglHandle   handle,
   int        bpp;
   CoglFramebuffer *framebuffer;
   int        viewport[4];
-  CoglBitmap alpha_bmp;
+  CoglBitmap *alpha_bmp;
   CoglHandle prev_source;
   CoglMatrixStack *projection_stack;
   CoglMatrixStack *modelview_stack;
+  int target_width = _cogl_bitmap_get_width (target_bmp);
+  int target_height = _cogl_bitmap_get_height (target_bmp);
+  int target_rowstride = _cogl_bitmap_get_rowstride (target_bmp);
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
@@ -1086,14 +1124,22 @@ _cogl_texture_draw_and_read (CoglHandle   handle,
       guint8 *srcpixel;
       guint8 *dstpixel;
       int     x,y;
+      int     alpha_rowstride = bpp * target_width;
+
+      if ((dstdata = _cogl_bitmap_map (target_bmp,
+                                       COGL_BUFFER_ACCESS_WRITE,
+                                       COGL_BUFFER_MAP_HINT_DISCARD)) == NULL)
+        return FALSE;
+
+      srcdata = g_malloc (alpha_rowstride * target_height);
 
       /* Create temp bitmap for alpha values */
-      alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
-      alpha_bmp.width = target_bmp->width;
-      alpha_bmp.height = target_bmp->height;
-      alpha_bmp.rowstride = bpp * alpha_bmp.width;
-      alpha_bmp.data = g_malloc (alpha_bmp.rowstride *
-                                 alpha_bmp.height);
+      alpha_bmp = _cogl_bitmap_new_from_data (srcdata,
+                                              COGL_PIXEL_FORMAT_RGBA_8888,
+                                              target_width, target_height,
+                                              alpha_rowstride,
+                                              (CoglBitmapDestroyNotify) g_free,
+                                              NULL);
 
       /* Draw alpha values into RGB channels */
       cogl_material_set_layer_combine (ctx->texture_download_material,
@@ -1101,25 +1147,25 @@ _cogl_texture_draw_and_read (CoglHandle   handle,
                                        "RGBA = REPLACE (TEXTURE[A])",
                                        NULL);
 
-      do_texture_draw_and_read (handle, &alpha_bmp, viewport);
+      do_texture_draw_and_read (handle, alpha_bmp, viewport);
 
       /* Copy temp R to target A */
-      srcdata = alpha_bmp.data;
-      dstdata = target_bmp->data;
 
-      for (y=0; y<target_bmp->height; ++y)
+      for (y=0; y<target_height; ++y)
         {
-          for (x=0; x<target_bmp->width; ++x)
+          for (x=0; x<target_width; ++x)
             {
               srcpixel = srcdata + x*bpp;
               dstpixel = dstdata + x*bpp;
               dstpixel[3] = srcpixel[0];
             }
-          srcdata += alpha_bmp.rowstride;
-          dstdata += target_bmp->rowstride;
+          srcdata += alpha_rowstride;
+          dstdata += target_rowstride;
         }
 
-      g_free (alpha_bmp.data);
+      _cogl_bitmap_unmap (target_bmp);
+
+      cogl_object_unref (alpha_bmp);
     }
 
   /* Restore old state */
@@ -1146,8 +1192,8 @@ cogl_texture_get_data (CoglHandle       handle,
   int              closest_bpp;
   GLenum           closest_gl_format;
   GLenum           closest_gl_type;
-  CoglBitmap       target_bmp;
-  CoglBitmap       new_bmp;
+  CoglBitmap      *target_bmp;
+  CoglBitmap      *new_bmp;
   gboolean         success;
   guint8          *src;
   guint8          *dst;
@@ -1156,7 +1202,7 @@ cogl_texture_get_data (CoglHandle       handle,
   int              tex_height;
 
   if (!cogl_is_texture (handle))
-    return FALSE;
+    return 0;
 
   tex = COGL_TEXTURE (handle);
 
@@ -1183,60 +1229,89 @@ cogl_texture_get_data (CoglHandle       handle,
                                                        &closest_gl_type);
   closest_bpp = _cogl_get_format_bpp (closest_format);
 
-  target_bmp.width = tex_width;
-  target_bmp.height = tex_height;
-
   /* Is the requested format supported? */
   if (closest_format == format)
+    /* Target user data directly */
+    target_bmp = _cogl_bitmap_new_from_data (data,
+                                             format,
+                                             tex_width,
+                                             tex_height,
+                                             rowstride,
+                                             NULL, NULL);
+  else
     {
-      /* Target user data directly */
-      target_bmp.format = format;
-      target_bmp.rowstride = rowstride;
-      target_bmp.data = data;
+      int target_rowstride = tex_width * closest_bpp;
+      guint8 *target_data = g_malloc (tex_height * target_rowstride);
+      target_bmp = _cogl_bitmap_new_from_data (target_data,
+                                               closest_format,
+                                               tex_width,
+                                               tex_height,
+                                               target_rowstride,
+                                               (CoglBitmapDestroyNotify) g_free,
+                                               NULL);
     }
-  else
+
+  if ((dst = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE,
+                               COGL_BUFFER_MAP_HINT_DISCARD)) == NULL)
     {
-      /* Target intermediate buffer */
-      target_bmp.format = closest_format;
-      target_bmp.rowstride = target_bmp.width * closest_bpp;
-      target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride);
+      cogl_object_unref (target_bmp);
+      return 0;
     }
 
-  if (!tex->vtable->get_data (tex,
-                              target_bmp.format,
-                              target_bmp.rowstride,
-                              target_bmp.data))
-    /* XXX: In some cases _cogl_texture_2d_download_from_gl may fail
-     * to read back the texture data; such as for GLES which doesn't
-     * support glGetTexImage, so here we fallback to drawing the
-     * texture and reading the pixels from the framebuffer. */
-    _cogl_texture_draw_and_read (tex, &target_bmp,
+  success = tex->vtable->get_data (tex,
+                                   closest_format,
+                                   rowstride,
+                                   dst);
+
+  _cogl_bitmap_unmap (target_bmp);
+
+  /* XXX: In some cases _cogl_texture_2d_download_from_gl may fail
+   * to read back the texture data; such as for GLES which doesn't
+   * support glGetTexImage, so here we fallback to drawing the
+   * texture and reading the pixels from the framebuffer. */
+  if (!success)
+    _cogl_texture_draw_and_read (tex, target_bmp,
                                  closest_gl_format,
                                  closest_gl_type);
 
   /* Was intermediate used? */
   if (closest_format != format)
     {
+      guint8 *new_bmp_data;
+      int new_bmp_rowstride;
+
       /* Convert to requested format */
-      success = _cogl_bitmap_convert_format_and_premult (&target_bmp,
-                                                         &new_bmp,
+      new_bmp = _cogl_bitmap_convert_format_and_premult (target_bmp,
                                                          format);
 
       /* Free intermediate data and return if failed */
-      g_free (target_bmp.data);
-      if (!success)
+      cogl_object_unref (target_bmp);
+
+      if (new_bmp == NULL)
         return 0;
 
+      new_bmp_rowstride = _cogl_bitmap_get_rowstride (new_bmp);
+      new_bmp_data = _cogl_bitmap_map (new_bmp, COGL_BUFFER_ACCESS_WRITE,
+                                       COGL_BUFFER_MAP_HINT_DISCARD);
+
+      if (new_bmp_data == NULL)
+        {
+          cogl_object_unref (new_bmp);
+          return 0;
+        }
+
       /* Copy to user buffer */
-      for (y = 0; y < new_bmp.height; ++y)
+      for (y = 0; y < tex_height; ++y)
         {
-          src = new_bmp.data + y * new_bmp.rowstride;
+          src = new_bmp_data + y * new_bmp_rowstride;
           dst = data + y * rowstride;
-          memcpy (dst, src, new_bmp.width * bpp);
+          memcpy (dst, src, tex_width * bpp);
         }
 
+      _cogl_bitmap_unmap (new_bmp);
+
       /* Free converted data */
-      g_free (new_bmp.data);
+      cogl_object_unref (new_bmp);
     }
 
   return byte_size;
index 5640204..4df0cdb 100644 (file)
@@ -617,12 +617,14 @@ cogl_read_pixels (int x,
                   guint8 *pixels)
 {
   CoglFramebuffer *framebuffer;
-  int        framebuffer_height;
-  int        bpp;
-  CoglBitmap bmp;
-  GLenum     gl_intformat;
-  GLenum     gl_format;
-  GLenum     gl_type;
+  int              framebuffer_height;
+  int              bpp;
+  CoglBitmap      *bmp;
+  GLenum           gl_intformat;
+  GLenum           gl_format;
+  GLenum           gl_type;
+  CoglPixelFormat  bmp_format;
+  int              rowstride;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -649,11 +651,8 @@ cogl_read_pixels (int x,
 
   /* Initialise the CoglBitmap */
   bpp = _cogl_get_format_bpp (format);
-  bmp.format = format;
-  bmp.data = pixels;
-  bmp.width = width;
-  bmp.height = height;
-  bmp.rowstride = bpp * width;
+  rowstride = bpp * width;
+  bmp_format = format;
 
   if ((format & COGL_A_BIT))
     {
@@ -667,9 +666,13 @@ cogl_read_pixels (int x,
          it. Eventually we may want to add a way for an application to
          inform Cogl that the framebuffer is not premultiplied in case
          it is being used for some special purpose. */
-      bmp.format |= COGL_PREMULT_BIT;
+      bmp_format |= COGL_PREMULT_BIT;
     }
 
+  bmp = _cogl_bitmap_new_from_data (pixels,
+                                    bmp_format, width, height, rowstride,
+                                    NULL, NULL);
+
   _cogl_pixel_format_to_gl (format, &gl_intformat, &gl_format, &gl_type);
 
   /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
@@ -683,33 +686,33 @@ cogl_read_pixels (int x,
 #ifndef COGL_HAS_GL
   if (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE)
     {
-      CoglBitmap tmp_bmp, dst_bmp;
+      CoglBitmap *tmp_bmp, *dst_bmp;
+      guint8 *tmp_data = g_malloc (width * height * 4);
 
-      tmp_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
-      tmp_bmp.data = g_malloc (width * height * 4);
-      tmp_bmp.width = width;
-      tmp_bmp.height = height;
-      tmp_bmp.rowstride = 4 * width;
+      tmp_bmp = _cogl_bitmap_new_from_data (tmp_data,
+                                            COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                                            width, height, 4 * width,
+                                            (CoglBitmapDestroyNotify) g_free,
+                                            NULL);
 
-      _cogl_texture_driver_prep_gl_for_pixels_download (tmp_bmp.rowstride, 4);
+      _cogl_texture_driver_prep_gl_for_pixels_download (4 * width, 4);
 
       GE( glReadPixels (x, y, width, height,
                         GL_RGBA, GL_UNSIGNED_BYTE,
-                        tmp_bmp.data) );
+                        tmp_data) );
 
       /* CoglBitmap doesn't currently have a way to convert without
          allocating its own buffer so we have to copy the data
          again */
-      if (_cogl_bitmap_convert_format_and_premult (&tmp_bmp,
-                                                   &dst_bmp,
-                                                   bmp.format))
+      if ((dst_bmp = _cogl_bitmap_convert_format_and_premult (tmp_bmp,
+                                                              bmp_format)))
         {
-          _cogl_bitmap_copy_subregion (&dst_bmp,
-                                       &bmp,
+          _cogl_bitmap_copy_subregion (dst_bmp,
+                                       bmp,
                                        0, 0,
                                        0, 0,
-                                       bmp.width, bmp.height);
-          g_free (dst_bmp.data);
+                                       width, height);
+          cogl_object_unref (dst_bmp);
         }
       else
         {
@@ -717,26 +720,26 @@ cogl_read_pixels (int x,
              just have to leave the data initialised */
         }
 
-      g_free (tmp_bmp.data);
+      cogl_object_unref (tmp_bmp);
     }
   else
 #endif
     {
-      _cogl_texture_driver_prep_gl_for_pixels_download (bmp.rowstride, bpp);
+      _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp);
 
       GE( glReadPixels (x, y, width, height, gl_format, gl_type, pixels) );
 
       /* Convert to the premult format specified by the caller
          in-place. This will do nothing if the premult status is already
          correct. */
-      _cogl_bitmap_convert_premult_status (&bmp, format);
+      _cogl_bitmap_convert_premult_status (bmp, format);
     }
 
   /* NB: All offscreen rendering is done upside down so there is no need
    * to flip in this case... */
   if (!cogl_is_offscreen (framebuffer))
     {
-      guint8 *temprow = g_alloca (bmp.rowstride * sizeof (guint8));
+      guint8 *temprow = g_alloca (rowstride * sizeof (guint8));
 
       /* TODO: consider using the GL_MESA_pack_invert extension in the future
        * to avoid this flip... */
@@ -747,15 +750,17 @@ cogl_read_pixels (int x,
           if (y != height - y - 1) /* skip center row */
             {
               memcpy (temprow,
-                      pixels + y * bmp.rowstride, bmp.rowstride);
-              memcpy (pixels + y * bmp.rowstride,
-                      pixels + (height - y - 1) * bmp.rowstride, bmp.rowstride);
-              memcpy (pixels + (height - y - 1) * bmp.rowstride,
+                      pixels + y * rowstride, rowstride);
+              memcpy (pixels + y * rowstride,
+                      pixels + (height - y - 1) * rowstride, rowstride);
+              memcpy (pixels + (height - y - 1) * rowstride,
                       temprow,
-                      bmp.rowstride);
+                      rowstride);
             }
         }
     }
+
+  cogl_object_unref (bmp);
 }
 
 static void
index 1244c5d..376584d 100644 (file)
@@ -153,23 +153,30 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                             GLuint       source_gl_format,
                                             GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
-
-  /* Setup gl alignment to match rowstride and top-left corner */
-  prep_gl_for_pixels_upload_full (source_bmp->rowstride,
-                                  0,
-                                  src_x,
-                                  src_y,
-                                  bpp);
-
-  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
-
-  GE( glTexSubImage2D (gl_target, 0,
-                       dst_x, dst_y,
-                       width, height,
-                       source_gl_format,
-                       source_gl_type,
-                       source_bmp->data) );
+  guint8 *data;
+
+  if ((data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
+
+      /* Setup gl alignment to match rowstride and top-left corner */
+      prep_gl_for_pixels_upload_full (_cogl_bitmap_get_rowstride (source_bmp),
+                                      0,
+                                      src_x,
+                                      src_y,
+                                      bpp);
+
+      _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
+
+      GE( glTexSubImage2D (gl_target, 0,
+                           dst_x, dst_y,
+                           width, height,
+                           source_gl_format,
+                           source_gl_type,
+                           data) );
+
+      _cogl_bitmap_unmap (source_bmp);
+    }
 }
 
 void
@@ -181,20 +188,29 @@ _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       source_gl_format,
                                    GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
+  guint8 *data;
 
-  /* Setup gl alignment to match rowstride and top-left corner */
-  prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, 0, bpp);
+  if ((data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
+
+      /* Setup gl alignment to match rowstride and top-left corner */
+      prep_gl_for_pixels_upload_full (_cogl_bitmap_get_rowstride (source_bmp),
+                                      0, 0, 0, bpp);
+
+      _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
-  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
+      GE( glTexImage2D (gl_target, 0,
+                        internal_gl_format,
+                        _cogl_bitmap_get_width (source_bmp),
+                        _cogl_bitmap_get_height (source_bmp),
+                        0,
+                        source_gl_format,
+                        source_gl_type,
+                        data) );
 
-  GE( glTexImage2D (gl_target, 0,
-                    internal_gl_format,
-                    source_bmp->width, source_bmp->height,
-                    0,
-                    source_gl_format,
-                    source_gl_type,
-                    source_bmp->data) );
+      _cogl_bitmap_unmap (source_bmp);
+    }
 }
 
 void
@@ -208,27 +224,35 @@ _cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
                                       GLuint       source_gl_format,
                                       GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
+  guint8 *data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  /* Setup gl alignment to match rowstride and top-left corner */
-  prep_gl_for_pixels_upload_full (source_bmp->rowstride,
-                                  source_bmp->height / depth,
-                                  0, 0, bpp);
-
-  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
-
-  GE( glTexImage3D (gl_target,
-                    0, /* level */
-                    internal_gl_format,
-                    source_bmp->width,
-                    height,
-                    depth,
-                    0,
-                    source_gl_format,
-                    source_gl_type,
-                    source_bmp->data) );
+  if ((data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
+
+      /* Setup gl alignment to match rowstride and top-left corner */
+      prep_gl_for_pixels_upload_full (_cogl_bitmap_get_rowstride (source_bmp),
+                                      (_cogl_bitmap_get_height (source_bmp) /
+                                       depth),
+                                      0, 0, bpp);
+
+      _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
+
+      GE( glTexImage3D (gl_target,
+                        0, /* level */
+                        internal_gl_format,
+                        _cogl_bitmap_get_width (source_bmp),
+                        height,
+                        depth,
+                        0,
+                        source_gl_format,
+                        source_gl_type,
+                        data) );
+
+      _cogl_bitmap_unmap (source_bmp);
+    }
 }
 
 gboolean
index 1c9a8f3..de704cf 100644 (file)
@@ -113,47 +113,58 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                             GLuint       source_gl_format,
                                             GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
-  CoglBitmap slice_bmp;
+  guint8 *data;
+  CoglPixelFormat source_format = _cogl_bitmap_get_format (source_bmp);
+  int bpp = _cogl_get_format_bpp (source_format);
+  CoglBitmap *slice_bmp;
+  int rowstride;
 
-  /* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_PIXELS
-   * or GL_UNPACK_SKIP_ROWS pixel store options so we can't directly source a
-   * sub-region from source_bmp, we need to use a transient bitmap instead. */
+  /* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH,
+   * GL_UNPACK_SKIP_PIXELS or GL_UNPACK_SKIP_ROWS pixel store options
+   * so we can't directly source a sub-region from source_bmp, we need
+   * to use a transient bitmap instead. */
 
-  /* FIXME: optimize by not copying to intermediate slice bitmap when source
-   * rowstride = bpp * width and the texture image is not sliced */
+  /* FIXME: optimize by not copying to intermediate slice bitmap when
+   * source rowstride = bpp * width and the texture image is not
+   * sliced */
 
   /* Setup temp bitmap for slice subregion */
-  slice_bmp.format = source_bmp->format;
-  slice_bmp.width  = width;
-  slice_bmp.height = height;
-  slice_bmp.rowstride = bpp * slice_bmp.width;
-  slice_bmp.data = g_malloc (slice_bmp.rowstride * slice_bmp.height);
+  rowstride = bpp * width;
+  slice_bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * height),
+                                          source_format,
+                                          width,
+                                          height,
+                                          rowstride,
+                                          (CoglBitmapDestroyNotify)
+                                          g_free,
+                                          NULL);
 
   /* Setup gl alignment to match rowstride and top-left corner */
-  _cogl_texture_driver_prep_gl_for_pixels_upload (slice_bmp.rowstride,
-                                                  bpp);
+  _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
 
   /* Copy subregion data */
   _cogl_bitmap_copy_subregion (source_bmp,
-                               &slice_bmp,
+                               slice_bmp,
                                src_x,
                                src_y,
                                0, 0,
-                               slice_bmp.width,
-                               slice_bmp.height);
+                               width, height);
 
-  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
+  if ((data = _cogl_bitmap_map (slice_bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
-  GE( glTexSubImage2D (gl_target, 0,
-                       dst_x, dst_y,
-                       width, height,
-                       source_gl_format,
-                       source_gl_type,
-                       slice_bmp.data) );
+      GE( glTexSubImage2D (gl_target, 0,
+                           dst_x, dst_y,
+                           width, height,
+                           source_gl_format,
+                           source_gl_type,
+                           data) );
 
-  /* Free temp bitmap */
-  g_free (slice_bmp.data);
+      _cogl_bitmap_unmap (slice_bmp);
+    }
+
+  cogl_object_unref (slice_bmp);
 }
 
 void
@@ -165,41 +176,53 @@ _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       source_gl_format,
                                    GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
-  CoglBitmap bmp = *source_bmp;
-  gboolean bmp_owner = FALSE;
+  int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
+  int rowstride = _cogl_bitmap_get_rowstride (source_bmp);
+  int bmp_width = _cogl_bitmap_get_width (source_bmp);
+  int bmp_height = _cogl_bitmap_get_height (source_bmp);
+  CoglBitmap *bmp;
+  guint8 *data;
 
   /* If the rowstride can't be specified with just GL_ALIGNMENT alone
      then we need to copy the bitmap because there is no GL_ROW_LENGTH */
-  if (source_bmp->rowstride / bpp != source_bmp->width)
+  if (rowstride / bpp != bmp_width)
     {
-      bmp.rowstride = bpp * bmp.width;
-      bmp.data = g_malloc (bmp.rowstride * bmp.height);
-      bmp_owner = TRUE;
+      bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * bmp_height),
+                                        _cogl_bitmap_get_format (source_bmp),
+                                        bmp_width,
+                                        bmp_height,
+                                        rowstride,
+                                        (CoglBitmapDestroyNotify) g_free,
+                                        NULL);
 
       _cogl_bitmap_copy_subregion (source_bmp,
-                                   &bmp,
+                                   bmp,
                                    0, 0, 0, 0,
-                                   bmp.width,
-                                   bmp.height);
+                                   bmp_width,
+                                   bmp_height);
     }
+  else
+    bmp = cogl_object_ref (source_bmp);
 
   /* Setup gl alignment to match rowstride and top-left corner */
-  _cogl_texture_driver_prep_gl_for_pixels_upload (bmp.rowstride,
-                                                  bpp);
+  _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
 
   _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
-  GE( glTexImage2D (gl_target, 0,
-                    internal_gl_format,
-                    bmp.width, bmp.height,
-                    0,
-                    source_gl_format,
-                    source_gl_type,
-                    bmp.data) );
+  if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      GE( glTexImage2D (gl_target, 0,
+                        internal_gl_format,
+                        bmp_width, bmp_height,
+                        0,
+                        source_gl_format,
+                        source_gl_type,
+                        data) );
+
+      _cogl_bitmap_unmap (bmp);
+    }
 
-  if (bmp_owner)
-    g_free (bmp.data);
+  cogl_object_unref (bmp);
 }
 
 void
@@ -213,7 +236,11 @@ _cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
                                       GLuint       source_gl_format,
                                       GLuint       source_gl_type)
 {
-  int bpp = _cogl_get_format_bpp (source_bmp->format);
+  int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
+  int rowstride = _cogl_bitmap_get_rowstride (source_bmp);
+  int bmp_width = _cogl_bitmap_get_width (source_bmp);
+  int bmp_height = _cogl_bitmap_get_height (source_bmp);
+  guint8 *data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -222,14 +249,14 @@ _cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
   /* If the rowstride or image height can't be specified with just
      GL_ALIGNMENT alone then we need to copy the bitmap because there
      is no GL_ROW_LENGTH */
-  if (source_bmp->rowstride / bpp != source_bmp->width ||
-      height != source_bmp->height / depth)
+  if (rowstride / bpp != bmp_width ||
+      height != bmp_height / depth)
     {
-      int image_height = source_bmp->height / depth;
+      CoglBitmap *bmp;
+      int image_height = bmp_height / depth;
       int i;
 
-      _cogl_texture_driver_prep_gl_for_pixels_upload (source_bmp->width * bpp,
-                                                      bpp);
+      _cogl_texture_driver_prep_gl_for_pixels_upload (bmp_width * bpp, bpp);
 
       /* Initialize the texture with empty data and then upload each
          image with a sub-region update */
@@ -237,7 +264,7 @@ _cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
       GE( glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
-                        source_bmp->width,
+                        bmp_width,
                         height,
                         depth,
                         0,
@@ -245,51 +272,60 @@ _cogl_texture_driver_upload_to_gl_3d (GLenum       gl_target,
                         source_gl_type,
                         NULL) );
 
+      bmp = _cogl_bitmap_new_from_data (g_malloc (bpp * bmp_width * height),
+                                        _cogl_bitmap_get_format (source_bmp),
+                                        bmp_width,
+                                        height,
+                                        bpp * bmp_width,
+                                        (CoglBitmapDestroyNotify) g_free,
+                                        NULL);
+
       for (i = 0; i < depth; i++)
         {
-          CoglBitmap bmp = *source_bmp;
-
-          bmp.rowstride = bpp * bmp.width;
-          bmp.height = height;
-          bmp.data = g_malloc (bmp.rowstride * bmp.height);
-
           _cogl_bitmap_copy_subregion (source_bmp,
-                                       &bmp,
+                                       bmp,
                                        0, image_height * i,
                                        0, 0,
-                                       bmp.width,
-                                       bmp.height);
-
-          GE( glTexSubImage3D (gl_target,
-                               0, /* level */
-                               0, /* xoffset */
-                               0, /* yoffset */
-                               i, /* zoffset */
-                               bmp.width, /* width */
-                               height, /* height */
-                               1, /* depth */
-                               source_gl_format,
-                               source_gl_type,
-                               bmp.data) );
-
-          g_free (bmp.data);
+                                       bmp_width,
+                                       bmp_height);
+
+          if ((data = _cogl_bitmap_map (bmp,
+                                        COGL_BUFFER_ACCESS_READ, 0)))
+            {
+              GE( glTexSubImage3D (gl_target,
+                                   0, /* level */
+                                   0, /* xoffset */
+                                   0, /* yoffset */
+                                   i, /* zoffset */
+                                   bmp_width, /* width */
+                                   height, /* height */
+                                   1, /* depth */
+                                   source_gl_format,
+                                   source_gl_type,
+                                   data) );
+
+              _cogl_bitmap_unmap (bmp);
+            }
         }
+
+      cogl_object_unref (bmp);
     }
-  else
+  else if ((data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0)))
     {
-      _cogl_texture_driver_prep_gl_for_pixels_upload (source_bmp->rowstride,
-                                                      bpp);
+      _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
 
       GE( glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
-                        source_bmp->width,
+                        bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
-                        source_bmp->data) );
+                        data) );
+
+      _cogl_bitmap_unmap (source_bmp);
     }
 }