[Cogl] [PATCH 01/11] texture: remove _cogl_texture_prepare_for_upload

Robert Bragg robert at sixbynine.org
Thu Jun 27 09:22:08 PDT 2013


From: Robert Bragg <robert at linux.intel.com>

This removes the gl centric _cogl_texture_prepare_for_upload api from
cogl-texture.c and instead adds a _cogl_bitmap_convert_for_upload() api
which everything now uses instead. GL specific code that needed the gl
internal/format/type enums returned by _cogl_texture_prepare_for_upload
now use ->pixel_format_to_gl directly.

Since there was a special case optimization in
cogl_texture_new_from_file that aimed to avoid copying the temporary
bitmap that's created for the given file and allow conversions to
happen in-place the new _cogl_bitmap_convert_for_upload() api supports
converting in place depending on a 'can_convert_in_place' argument.

This ability to convert bitmaps in-place has been integrated across the
different components as appropriate.

In updating cogl-texture-2d-sliced.c this was able to remove a number of
other GL specific parts to how spans are setup.
---
 cogl/cogl-atlas-texture-private.h             |   1 +
 cogl/cogl-atlas-texture.c                     |  70 +++++++-------
 cogl/cogl-auto-texture.c                      |  55 ++++++-----
 cogl/cogl-bitmap-conversion.c                 |  79 ++++++++++++++++
 cogl/cogl-bitmap-private.h                    |   6 ++
 cogl/cogl-driver.h                            |   1 +
 cogl/cogl-texture-2d-private.h                |   6 ++
 cogl/cogl-texture-2d-sliced-private.h         |   1 +
 cogl/cogl-texture-2d-sliced.c                 | 128 ++++++++++----------------
 cogl/cogl-texture-2d.c                        |  16 +++-
 cogl/cogl-texture-3d.c                        |  46 +++++----
 cogl/cogl-texture-private.h                   |  21 +----
 cogl/cogl-texture-rectangle.c                 |  67 ++++++++------
 cogl/cogl-texture.c                           |  86 -----------------
 cogl/cogl.symbols                             |   1 -
 cogl/driver/gl/cogl-texture-2d-gl-private.h   |   1 +
 cogl/driver/gl/cogl-texture-2d-gl.c           |  76 +++++++++------
 cogl/driver/nop/cogl-texture-2d-nop-private.h |   1 +
 cogl/driver/nop/cogl-texture-2d-nop.c         |   1 +
 19 files changed, 345 insertions(+), 318 deletions(-)

diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl-atlas-texture-private.h
index 670eea4..75c740e 100644
--- a/cogl/cogl-atlas-texture-private.h
+++ b/cogl/cogl-atlas-texture-private.h
@@ -61,6 +61,7 @@ CoglAtlasTexture *
 _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
                                      CoglTextureFlags flags,
                                      CoglPixelFormat internal_format,
+                                     CoglBool can_convert_in_place,
                                      CoglError **error);
 
 CoglAtlasTexture *
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c
index 747a6c9..b390cc2 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl-atlas-texture.c
@@ -510,12 +510,13 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
 }
 
 static CoglBitmap *
-_cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex,
-                                        CoglBitmap *bmp,
-                                        CoglError **error)
+_cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex,
+                                               CoglBitmap *bmp,
+                                               CoglBool can_convert_in_place,
+                                               CoglError **error)
 {
   CoglPixelFormat internal_format;
-  CoglBitmap *converted_bmp;
+  CoglBitmap *upload_bmp;
   CoglBitmap *override_bmp;
 
   /* We'll prepare to upload using the format of the actual texture of
@@ -529,15 +530,11 @@ _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex,
   internal_format = (COGL_PIXEL_FORMAT_RGBA_8888 |
                      (atlas_tex->format & COGL_PREMULT_BIT));
 
-  converted_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                                    internal_format,
-                                                    NULL, /* dst_format_out */
-                                                    NULL, /* glintformat */
-                                                    NULL, /* glformat */
-                                                    NULL, /* gltype */
-                                                    error);
-
-  if (converted_bmp == NULL)
+  upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+                                                internal_format,
+                                                can_convert_in_place,
+                                                error);
+  if (upload_bmp == NULL)
     return NULL;
 
   /* We'll create another bitmap which uses the same data but
@@ -545,14 +542,14 @@ _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex,
      to the atlas texture won't trigger the conversion again */
 
   override_bmp =
-    _cogl_bitmap_new_shared (converted_bmp,
-                             cogl_bitmap_get_format (converted_bmp) &
+    _cogl_bitmap_new_shared (upload_bmp,
+                             cogl_bitmap_get_format (upload_bmp) &
                              ~COGL_PREMULT_BIT,
-                             cogl_bitmap_get_width (converted_bmp),
-                             cogl_bitmap_get_height (converted_bmp),
-                             cogl_bitmap_get_rowstride (converted_bmp));
+                             cogl_bitmap_get_width (upload_bmp),
+                             cogl_bitmap_get_height (upload_bmp),
+                             cogl_bitmap_get_rowstride (upload_bmp));
 
-  cogl_object_unref (converted_bmp);
+  cogl_object_unref (upload_bmp);
 
   return override_bmp;
 }
@@ -579,11 +576,13 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
   if (atlas_tex->atlas)
     {
       CoglBool ret;
-
-      bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex,
-                                                    bmp,
-                                                    error);
-      if (!bmp)
+      CoglBitmap *upload_bmp =
+        _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
+                                                       bmp,
+                                                       FALSE, /* can't convert
+                                                                 in place */
+                                                       error);
+      if (!upload_bmp)
         return FALSE;
 
       /* Upload the data ignoring the premult bit */
@@ -591,10 +590,10 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
                                                         src_x, src_y,
                                                         dst_x, dst_y,
                                                         dst_width, dst_height,
-                                                        bmp,
+                                                        upload_bmp,
                                                         error);
 
-      cogl_object_unref (bmp);
+      cogl_object_unref (upload_bmp);
 
       return ret;
     }
@@ -788,11 +787,12 @@ CoglAtlasTexture *
 _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
                                      CoglTextureFlags flags,
                                      CoglPixelFormat internal_format,
+                                     CoglBool can_convert_in_place,
                                      CoglError **error)
 {
   CoglContext *ctx = _cogl_bitmap_get_context (bmp);
   CoglAtlasTexture *atlas_tex;
-  CoglBitmap *dst_bmp;
+  CoglBitmap *upload_bmp;
   int bmp_width;
   int bmp_height;
   CoglPixelFormat bmp_format;
@@ -819,10 +819,12 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
       return NULL;
     }
 
-  dst_bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex,
-                                                    bmp,
-                                                    error);
-  if (dst_bmp == NULL)
+  upload_bmp =
+    _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
+                                                   bmp,
+                                                   can_convert_in_place,
+                                                   error);
+  if (upload_bmp == NULL)
     {
       cogl_object_unref (atlas_tex);
       return NULL;
@@ -837,15 +839,15 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
                                                    0, /* dst_y */
                                                    bmp_width, /* dst_width */
                                                    bmp_height, /* dst_height */
-                                                   dst_bmp,
+                                                   upload_bmp,
                                                    error))
     {
-      cogl_object_unref (dst_bmp);
+      cogl_object_unref (upload_bmp);
       cogl_object_unref (atlas_tex);
       return NULL;
     }
 
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
 
   return atlas_tex;
 }
diff --git a/cogl/cogl-auto-texture.c b/cogl/cogl-auto-texture.c
index 402cfb9..166e6a5 100644
--- a/cogl/cogl-auto-texture.c
+++ b/cogl/cogl-auto-texture.c
@@ -34,6 +34,7 @@
 #include "cogl-texture.h"
 #include "cogl-util.h"
 #include "cogl-texture-2d.h"
+#include "cogl-texture-2d-private.h"
 #include "cogl-primitive-texture.h"
 #include "cogl-texture-2d-sliced-private.h"
 #include "cogl-private.h"
@@ -134,11 +135,12 @@ cogl_texture_new_from_data (CoglContext *ctx,
   return tex;
 }
 
-CoglTexture *
-cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
-                              CoglTextureFlags flags,
-                              CoglPixelFormat internal_format,
-                              CoglError **error)
+static CoglTexture *
+_cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
+                               CoglTextureFlags flags,
+                               CoglPixelFormat internal_format,
+                               CoglBool can_convert_in_place,
+                               CoglError **error)
 {
   CoglContext *ctx = _cogl_bitmap_get_context (bitmap);
   CoglAtlasTexture *atlas_tex;
@@ -149,6 +151,7 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
   if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap,
                                                         flags,
                                                         internal_format,
+                                                        can_convert_in_place,
                                                         &internal_error)))
     return COGL_TEXTURE (atlas_tex);
 
@@ -161,9 +164,10 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
       (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
        cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
     {
-      tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap,
-                                                           internal_format,
-                                                           &internal_error));
+      tex = COGL_TEXTURE (_cogl_texture_2d_new_from_bitmap (bitmap,
+                                                            internal_format,
+                                                            can_convert_in_place,
+                                                            &internal_error));
 
       if (!tex)
         {
@@ -186,6 +190,7 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
       tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                              flags,
                                                              internal_format,
+                                                             can_convert_in_place,
                                                              error));
     }
 
@@ -193,6 +198,19 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
 }
 
 CoglTexture *
+cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
+                              CoglTextureFlags flags,
+                              CoglPixelFormat internal_format,
+                              CoglError **error)
+{
+  return _cogl_texture_new_from_bitmap (bitmap,
+                                        flags,
+                                        internal_format,
+                                        FALSE, /* can't convert in-place */
+                                        error);
+}
+
+CoglTexture *
 cogl_texture_new_from_file (CoglContext *ctx,
                             const char *filename,
                             CoglTextureFlags flags,
@@ -201,7 +219,6 @@ cogl_texture_new_from_file (CoglContext *ctx,
 {
   CoglBitmap *bmp;
   CoglTexture *texture = NULL;
-  CoglPixelFormat src_format;
 
   _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL);
 
@@ -209,22 +226,10 @@ cogl_texture_new_from_file (CoglContext *ctx,
   if (bmp == NULL)
     return NULL;
 
-  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 (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,
-                                           error))
-    {
-      texture =
-        cogl_texture_new_from_bitmap (bmp, flags, internal_format, error);
-    }
+  texture = _cogl_texture_new_from_bitmap (bmp, flags,
+                                           internal_format,
+                                           TRUE, /* can convert in-place */
+                                           error);
 
   cogl_object_unref (bmp);
 
diff --git a/cogl/cogl-bitmap-conversion.c b/cogl/cogl-bitmap-conversion.c
index 102bf23..7bc2f1d 100644
--- a/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl-bitmap-conversion.c
@@ -504,6 +504,85 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
   return dst_bmp;
 }
 
+CoglBitmap *
+_cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp,
+                                 CoglPixelFormat internal_format,
+                                 CoglBool can_convert_in_place,
+                                 CoglError **error)
+{
+  CoglContext *ctx = _cogl_bitmap_get_context (src_bmp);
+  CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
+  CoglBitmap *dst_bmp;
+
+  _COGL_RETURN_VAL_IF_FAIL (internal_format != COGL_PIXEL_FORMAT_ANY, NULL);
+
+  /* OpenGL supports specifying a different format for the internal
+     format when uploading texture data. We should use this to convert
+     formats because it is likely to be faster and support more types
+     than the Cogl bitmap code. However under GLES the internal format
+     must be the same as the bitmap format and it only supports a
+     limited number of formats so we must convert using the Cogl
+     bitmap code instead */
+
+  /* If the driver doesn't natively support alpha textures then it
+   * won't work correctly to convert to/from component-alpha
+   * textures */
+
+  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FORMAT_CONVERSION) &&
+      ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) ||
+       (src_format != COGL_PIXEL_FORMAT_A_8 &&
+        internal_format != COGL_PIXEL_FORMAT_A_8) ||
+       src_format == internal_format))
+    {
+      /* If the source format does not have the same premult flag as the
+         internal_format then we need to copy and convert it */
+      if (_cogl_texture_needs_premult_conversion (src_format,
+                                                  internal_format))
+        {
+          if (can_convert_in_place)
+            {
+              if (_cogl_bitmap_convert_premult_status (src_bmp,
+                                                       (src_format ^
+                                                        COGL_PREMULT_BIT),
+                                                       error))
+                {
+                  dst_bmp = cogl_object_ref (src_bmp);
+                }
+              else
+                return NULL;
+            }
+          else
+            {
+              dst_bmp = _cogl_bitmap_convert (src_bmp,
+                                              src_format ^ COGL_PREMULT_BIT,
+                                              error);
+              if (dst_bmp == NULL)
+                return NULL;
+            }
+        }
+      else
+        dst_bmp = cogl_object_ref (src_bmp);
+    }
+  else
+    {
+      CoglPixelFormat closest_format;
+
+      closest_format =
+        ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                                internal_format,
+                                                NULL, /* ignore gl intformat */
+                                                NULL, /* ignore gl format */
+                                                NULL); /* ignore gl type */
+
+      if (closest_format != src_format)
+        dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format, error);
+      else
+        dst_bmp = cogl_object_ref (src_bmp);
+    }
+
+  return dst_bmp;
+}
+
 CoglBool
 _cogl_bitmap_unpremult (CoglBitmap *bmp,
                         CoglError **error)
diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h
index ae96aaf..34ad4cf 100644
--- a/cogl/cogl-bitmap-private.h
+++ b/cogl/cogl-bitmap-private.h
@@ -105,6 +105,12 @@ _cogl_bitmap_convert (CoglBitmap *bmp,
 		      CoglPixelFormat dst_format,
                       CoglError **error);
 
+CoglBitmap *
+_cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp,
+                                 CoglPixelFormat internal_format,
+                                 CoglBool can_convert_in_place,
+                                 CoglError **error);
+
 CoglBool
 _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
                                   CoglBitmap *dst_bmp,
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index e90e6fa..4642236 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -148,6 +148,7 @@ struct _CoglDriverVtable
   CoglTexture2D *
   (* texture_2d_new_from_bitmap) (CoglBitmap *bmp,
                                   CoglPixelFormat internal_format,
+                                  CoglBool can_convert_in_place,
                                   CoglError **error);
 
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index 12e5820..5d193bc 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -59,6 +59,12 @@ struct _CoglTexture2D
   CoglTexturePixel first_pixel;
 };
 
+CoglTexture2D *
+_cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
+                                  CoglPixelFormat internal_format,
+                                  CoglBool can_convert_in_place,
+                                  CoglError **error);
+
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
 /* NB: The reason we require the width, height and format to be passed
  * even though they may seem redundant is because GLES 1/2 don't
diff --git a/cogl/cogl-texture-2d-sliced-private.h b/cogl/cogl-texture-2d-sliced-private.h
index fbfd198..2d5106f 100644
--- a/cogl/cogl-texture-2d-sliced-private.h
+++ b/cogl/cogl-texture-2d-sliced-private.h
@@ -56,6 +56,7 @@ CoglTexture2DSliced *
 _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat internal_format,
+                                         CoglBool can_convert_in_place,
                                          CoglError **error);
 
 #endif /* __COGL_TEXTURE_2D_SLICED_PRIVATE_H */
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index 6189214..88e0553 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -332,9 +332,9 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
 }
 
 static CoglBool
-_cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
-                                      CoglBitmap *bmp,
-                                      CoglError **error)
+_cogl_texture_2d_sliced_upload_bitmap (CoglTexture2DSliced *tex_2ds,
+                                       CoglBitmap *bmp,
+                                       CoglError **error)
 {
   CoglSpan *x_span;
   CoglSpan *y_span;
@@ -422,17 +422,15 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
 }
 
 static CoglBool
-_cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
-                                                int src_x,
-                                                int src_y,
-                                                int dst_x,
-                                                int dst_y,
-                                                int width,
-                                                int height,
-                                                CoglBitmap *source_bmp,
-                                                GLuint source_gl_format,
-                                                GLuint source_gl_type,
-                                                CoglError **error)
+_cogl_texture_2d_sliced_upload_subregion (CoglTexture2DSliced *tex_2ds,
+                                          int src_x,
+                                          int src_y,
+                                          int dst_x,
+                                          int dst_y,
+                                          int width,
+                                          int height,
+                                          CoglBitmap *source_bmp,
+                                          CoglError **error)
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2ds);
   CoglSpan *x_span;
@@ -667,16 +665,13 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
                                      int width,
                                      int height,
                                      int max_waste,
-                                     CoglPixelFormat format,
+                                     CoglPixelFormat internal_format,
                                      CoglError **error)
 {
   int max_width;
   int max_height;
   int n_x_slices;
   int n_y_slices;
-  GLenum gl_intformat;
-  GLenum gl_format;
-  GLenum gl_type;
 
   int   (*slices_for_size) (int, int, int, GArray*);
 
@@ -694,25 +689,16 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
       slices_for_size = _cogl_pot_slices_for_size;
     }
 
-  ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                          format,
-                                          &gl_intformat,
-                                          &gl_format,
-                                          &gl_type);
-
   /* Negative number means no slicing forced by the user */
   if (max_waste <= -1)
     {
       CoglSpan span;
 
       /* Check if size supported else bail out */
-      if (!ctx->texture_driver->size_supported (ctx,
-                                                GL_TEXTURE_2D,
-                                                gl_intformat,
-                                                gl_format,
-                                                gl_type,
-                                                max_width,
-                                                max_height))
+      if (!ctx->driver_vtable->texture_2d_can_create (ctx,
+                                                      max_width,
+                                                      max_height,
+                                                      internal_format))
         {
           _cogl_set_error (error,
                            COGL_TEXTURE_ERROR,
@@ -749,13 +735,10 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
   else
     {
       /* Decrease the size of largest slice until supported by GL */
-      while (!ctx->texture_driver->size_supported (ctx,
-                                                   GL_TEXTURE_2D,
-                                                   gl_intformat,
-                                                   gl_format,
-                                                   gl_type,
-                                                   max_width,
-                                                   max_height))
+      while (!ctx->driver_vtable->texture_2d_can_create (ctx,
+                                                         max_width,
+                                                         max_height,
+                                                         internal_format))
         {
           /* Alternate between width and height */
           if (max_width > max_height)
@@ -975,14 +958,12 @@ CoglTexture2DSliced *
 _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
                                          CoglTextureFlags flags,
                                          CoglPixelFormat internal_format,
+                                         CoglBool can_convert_in_place,
                                          CoglError **error)
 {
   CoglContext *ctx;
   CoglTexture2DSliced *tex_2ds;
-  CoglBitmap *dst_bmp;
-  GLenum gl_intformat;
-  GLenum gl_format;
-  GLenum gl_type;
+  CoglBitmap *upload_bmp;
   int width, height, max_waste;
   int i;
 
@@ -1001,14 +982,15 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
   else
     max_waste = COGL_TEXTURE_MAX_WASTE;
 
-  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                              internal_format,
-                                              &internal_format,
-                                              &gl_intformat,
-                                              &gl_format,
-                                              &gl_type,
-                                              error);
-  if (dst_bmp == NULL)
+  internal_format =
+    _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
+                                             internal_format);
+
+  upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+                                                internal_format,
+                                                can_convert_in_place,
+                                                error);
+  if (upload_bmp == NULL)
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
       return NULL;
@@ -1027,12 +1009,12 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
   if (!cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error))
     goto error;
 
-  if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
-                                             dst_bmp,
-                                             error))
+  if (!_cogl_texture_2d_sliced_upload_bitmap (tex_2ds,
+                                              upload_bmp,
+                                              error))
     goto error;
 
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
 
   if ((flags & COGL_TEXTURE_NO_AUTO_MIPMAP))
     for (i = 0; i < tex_2ds->slice_textures->len; i++)
@@ -1049,7 +1031,7 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
   return _cogl_texture_2d_sliced_object_new (tex_2ds);
 
  error:
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
   _cogl_texture_2d_sliced_free (tex_2ds);
   return NULL;
 }
@@ -1351,32 +1333,24 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
                                     CoglError **error)
 {
   CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
-  GLenum gl_format;
-  GLenum gl_type;
+  CoglBitmap *upload_bmp;
   CoglBool status;
 
-  bmp = _cogl_texture_prepare_for_upload (bmp,
-                                          cogl_texture_get_format (tex),
-                                          NULL,
-                                          NULL,
-                                          &gl_format,
-                                          &gl_type,
-                                          error);
-  if (!bmp)
+  upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+                                                cogl_texture_get_format (tex),
+                                                FALSE, /* can't convert in
+                                                          place */
+                                                error);
+  if (!upload_bmp)
     return FALSE;
 
-  /* Send data to GL */
-  status =
-    _cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
-                                                    src_x, src_y,
-                                                    dst_x, dst_y,
-                                                    dst_width, dst_height,
-                                                    bmp,
-                                                    gl_format,
-                                                    gl_type,
-                                                    error);
-
-  cogl_object_unref (bmp);
+  status = _cogl_texture_2d_sliced_upload_subregion (tex_2ds,
+                                                     src_x, src_y,
+                                                     dst_x, dst_y,
+                                                     dst_width, dst_height,
+                                                     upload_bmp,
+                                                     error);
+  cogl_object_unref (upload_bmp);
 
   return status;
 }
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index a9ca01e..38e6212 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -150,9 +150,10 @@ _cogl_texture_2d_allocate (CoglTexture *tex,
 }
 
 CoglTexture2D *
-cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
-                                 CoglPixelFormat internal_format,
-                                 CoglError **error)
+_cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
+                                  CoglPixelFormat internal_format,
+                                  CoglBool can_convert_in_place,
+                                  CoglError **error)
 {
   CoglContext *ctx;
 
@@ -178,10 +179,19 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
 
   return ctx->driver_vtable->texture_2d_new_from_bitmap (bmp,
                                                          internal_format,
+                                                         can_convert_in_place,
                                                          error);
 }
 
 CoglTexture2D *
+cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
+                                 CoglPixelFormat internal_format,
+                                 CoglError **error)
+{
+  return _cogl_texture_2d_new_from_bitmap (bmp, internal_format, FALSE, error);
+}
+
+CoglTexture2D *
 cogl_texture_2d_new_from_data (CoglContext *ctx,
                                int width,
                                int height,
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
index 7f29549..83f85c1 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl-texture-3d.c
@@ -279,8 +279,9 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
                                  CoglError **error)
 {
   CoglTexture3D *tex_3d;
-  CoglBitmap *dst_bmp;
+  CoglBitmap *upload_bmp;
   CoglPixelFormat bmp_format;
+  CoglPixelFormat upload_format;
   unsigned int bmp_width;
   GLenum gl_intformat;
   GLenum gl_format;
@@ -301,16 +302,27 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
                                     error))
     return NULL;
 
-  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                              internal_format,
-                                              &internal_format,
-                                              &gl_intformat,
-                                              &gl_format,
-                                              &gl_type,
-                                              error);
-  if (dst_bmp == NULL)
+  upload_bmp =
+    _cogl_bitmap_convert_for_upload (bmp,
+                                     internal_format,
+                                     FALSE, /* can't convert in place */
+                                     error);
+  if (upload_bmp == NULL)
     return NULL;
 
+  upload_format = cogl_bitmap_get_format (upload_bmp);
+
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          upload_format,
+                                          NULL, /* internal format */
+                                          &gl_format,
+                                          &gl_type);
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          internal_format,
+                                          &gl_intformat,
+                                          NULL,
+                                          NULL);
+
   tex_3d = _cogl_texture_3d_create_base (ctx,
                                          bmp_width, height, depth,
                                          internal_format);
@@ -320,20 +332,18 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
     {
       CoglError *ignore = NULL;
-      uint8_t *data = _cogl_bitmap_map (dst_bmp,
+      uint8_t *data = _cogl_bitmap_map (upload_bmp,
                                         COGL_BUFFER_ACCESS_READ, 0,
                                         &ignore);
 
-      CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
-
       tex_3d->first_pixel.gl_format = gl_format;
       tex_3d->first_pixel.gl_type = gl_type;
 
       if (data)
         {
           memcpy (tex_3d->first_pixel.data, data,
-                  _cogl_pixel_format_get_bytes_per_pixel (format));
-          _cogl_bitmap_unmap (dst_bmp);
+                  _cogl_pixel_format_get_bytes_per_pixel (upload_format));
+          _cogl_bitmap_unmap (upload_bmp);
         }
       else
         {
@@ -341,7 +351,7 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
                      "glGenerateMipmap fallback");
           cogl_error_free (ignore);
           memset (tex_3d->first_pixel.data, 0,
-                  _cogl_pixel_format_get_bytes_per_pixel (format));
+                  _cogl_pixel_format_get_bytes_per_pixel (upload_format));
         }
     }
 
@@ -354,20 +364,20 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
                                              FALSE, /* is_foreign */
                                              height,
                                              depth,
-                                             dst_bmp,
+                                             upload_bmp,
                                              gl_intformat,
                                              gl_format,
                                              gl_type,
                                              error))
     {
-      cogl_object_unref (dst_bmp);
+      cogl_object_unref (upload_bmp);
       cogl_object_unref (tex_3d);
       return NULL;
     }
 
   tex_3d->gl_format = gl_intformat;
 
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
 
   _cogl_texture_set_allocated (COGL_TEXTURE (tex_3d), TRUE);
 
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h
index 2dfbf20..1f7476f 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl-texture-private.h
@@ -65,9 +65,9 @@ struct _CoglTextureVtable
 
   /* This should update the specified sub region of the texture with a
      sub region of the given bitmap. The bitmap is not converted
-     before being passed so the implementation is expected to call
-     _cogl_texture_prepare_for_upload with a suitable destination
-     format before uploading */
+     before being set so the caller is expected to have called
+     _cogl_bitmap_convert_for_upload with a suitable internal_format
+     before passing here */
   CoglBool (* set_region) (CoglTexture *tex,
                            int src_x,
                            int src_y,
@@ -225,21 +225,6 @@ CoglPixelFormat
 _cogl_texture_determine_internal_format (CoglPixelFormat src_format,
                                          CoglPixelFormat dst_format);
 
-/* Utility function to help uploading a bitmap. If the bitmap needs
- * premult conversion then a converted copy will be returned,
- * otherwise a reference to the original source will be returned.
- *
- * The GLenums needed for uploading are returned
- */
-CoglBitmap *
-_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
-                                  CoglPixelFormat dst_format,
-                                  CoglPixelFormat *dst_format_out,
-                                  GLenum *out_glintformat,
-                                  GLenum *out_glformat,
-                                  GLenum *out_gltype,
-                                  CoglError **error);
-
 CoglBool
 _cogl_texture_is_foreign (CoglTexture *texture);
 
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
index f81ecab..d006085 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl-texture-rectangle.c
@@ -261,11 +261,11 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
                                         CoglError **error)
 {
   CoglTextureRectangle *tex_rect;
-  CoglBitmap           *dst_bmp;
-  GLenum                gl_intformat;
-  GLenum                gl_format;
-  GLenum                gl_type;
-  CoglContext          *ctx;
+  CoglBitmap *upload_bmp;
+  GLenum gl_intformat;
+  GLenum gl_format;
+  GLenum gl_type;
+  CoglContext *ctx;
 
   _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
 
@@ -282,17 +282,25 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
                                            error))
     return NULL;
 
-  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                              internal_format,
-                                              &internal_format,
-                                              &gl_intformat,
-                                              &gl_format,
-                                              &gl_type,
-                                              error);
-
-  if (dst_bmp == NULL)
+  upload_bmp =
+    _cogl_bitmap_convert_for_upload (bmp,
+                                     internal_format,
+                                     FALSE, /* can't convert in place */
+                                     error);
+  if (upload_bmp == NULL)
     return NULL;
 
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          cogl_bitmap_get_format (upload_bmp),
+                                          NULL, /* internal format */
+                                          &gl_format,
+                                          &gl_type);
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          internal_format,
+                                          &gl_intformat,
+                                          NULL,
+                                          NULL);
+
   tex_rect = _cogl_texture_rectangle_create_base (ctx,
                                                   cogl_bitmap_get_width (bmp),
                                                   cogl_bitmap_get_height (bmp),
@@ -306,20 +314,20 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
                                           GL_TEXTURE_RECTANGLE_ARB,
                                           tex_rect->gl_texture,
                                           FALSE,
-                                          dst_bmp,
+                                          upload_bmp,
                                           gl_intformat,
                                           gl_format,
                                           gl_type,
                                           error))
     {
-      cogl_object_unref (dst_bmp);
+      cogl_object_unref (upload_bmp);
       cogl_object_unref (tex_rect);
       return NULL;
     }
 
   tex_rect->gl_format = gl_intformat;
 
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
 
   _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
 
@@ -564,21 +572,26 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
                                     CoglBitmap *bmp,
                                     CoglError **error)
 {
+  CoglBitmap *upload_bmp;
   GLenum gl_format;
   GLenum gl_type;
   CoglContext *ctx = tex->context;
   CoglBool status;
 
-  bmp = _cogl_texture_prepare_for_upload (bmp,
-                                          cogl_texture_get_format (tex),
-                                          NULL,
-                                          NULL,
-                                          &gl_format,
-                                          &gl_type,
-                                          error);
-  if (!bmp)
+  upload_bmp =
+    _cogl_bitmap_convert_for_upload (bmp,
+                                     cogl_texture_get_format (tex),
+                                     FALSE, /* can't convert in place */
+                                     error);
+  if (upload_bmp == NULL)
     return FALSE;
 
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          cogl_bitmap_get_format (upload_bmp),
+                                          NULL, /* internal format */
+                                          &gl_format,
+                                          &gl_type);
+
   /* Send data to GL */
   status =
     ctx->texture_driver->upload_subregion_to_gl (ctx,
@@ -588,12 +601,12 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
                                                  dst_x, dst_y,
                                                  dst_width, dst_height,
                                                  level,
-                                                 bmp,
+                                                 upload_bmp,
                                                  gl_format,
                                                  gl_type,
                                                  error);
 
-  cogl_object_unref (bmp);
+  cogl_object_unref (upload_bmp);
 
   return status;
 }
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 2c7dc5e..64398f4 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -161,92 +161,6 @@ _cogl_texture_determine_internal_format (CoglPixelFormat src_format,
     return dst_format;
 }
 
-CoglBitmap *
-_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
-                                  CoglPixelFormat dst_format,
-                                  CoglPixelFormat *dst_format_out,
-                                  GLenum *out_glintformat,
-                                  GLenum *out_glformat,
-                                  GLenum *out_gltype,
-                                  CoglError **error)
-{
-  CoglContext *ctx = _cogl_bitmap_get_context (src_bmp);
-  CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
-  CoglBitmap *dst_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
-     formats because it is likely to be faster and support more types
-     than the Cogl bitmap code. However under GLES the internal format
-     must be the same as the bitmap format and it only supports a
-     limited number of formats so we must convert using the Cogl
-     bitmap code instead */
-
-  /* If the driver doesn't natively support alpha textures then it
-   * won't work correctly to convert to/from component-alpha
-   * textures */
-
-  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FORMAT_CONVERSION) &&
-      ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) ||
-       (src_format != COGL_PIXEL_FORMAT_A_8 &&
-        dst_format != COGL_PIXEL_FORMAT_A_8) ||
-       src_format == dst_format))
-    {
-      /* 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_format,
-                                                  dst_format))
-        {
-          dst_bmp = _cogl_bitmap_convert (src_bmp,
-                                          src_format ^ COGL_PREMULT_BIT,
-                                          error);
-
-          if (dst_bmp == NULL)
-            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 */
-      ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                              src_format,
-                                              NULL, /* internal format */
-                                              out_glformat,
-                                              out_gltype);
-      ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                              dst_format,
-                                              out_glintformat,
-                                              NULL,
-                                              NULL);
-
-    }
-  else
-    {
-      CoglPixelFormat closest_format;
-
-      closest_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                                               dst_format,
-                                                               out_glintformat,
-                                                               out_glformat,
-                                                               out_gltype);
-
-      if (closest_format != src_format)
-        dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format, error);
-      else
-        dst_bmp = cogl_object_ref (src_bmp);
-    }
-
-  if (dst_format_out)
-    *dst_format_out = dst_format;
-
-  return dst_bmp;
-}
-
 CoglBool
 _cogl_texture_is_foreign (CoglTexture *texture)
 {
diff --git a/cogl/cogl.symbols b/cogl/cogl.symbols
index 714ef15..89a2bd8 100644
--- a/cogl/cogl.symbols
+++ b/cogl/cogl.symbols
@@ -663,7 +663,6 @@ _cogl_texture_get_associated_framebuffers
 _cogl_texture_get_gl_format
 _cogl_texture_init
 _cogl_texture_is_foreign
-_cogl_texture_prepare_for_upload
 _cogl_texture_gl_prep_alignment_for_pixels_upload
 _cogl_texture_pre_paint
 _cogl_texture_register_texture_type
diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h
index c71908f..0bab9e2 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl-private.h
+++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h
@@ -51,6 +51,7 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
 CoglTexture2D *
 _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
                                      CoglPixelFormat internal_format,
+                                     CoglBool can_convert_in_place,
                                      CoglError **error);
 
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
index a8a51a4..a793b9f 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -151,25 +151,34 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
 CoglTexture2D *
 _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
                                      CoglPixelFormat internal_format,
+                                     CoglBool can_convert_in_place,
                                      CoglError **error)
 {
   CoglContext *ctx = _cogl_bitmap_get_context (bmp);
   CoglTexture2D *tex_2d;
-  CoglBitmap *dst_bmp;
+  CoglBitmap *upload_bmp;
   GLenum gl_intformat;
   GLenum gl_format;
   GLenum gl_type;
 
-  dst_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                              internal_format,
-                                              &internal_format,
-                                              &gl_intformat,
-                                              &gl_format,
-                                              &gl_type,
-                                              error);
-  if (!dst_bmp)
+  upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+                                                internal_format,
+                                                can_convert_in_place,
+                                                error);
+  if (upload_bmp == NULL)
     return NULL;
 
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          cogl_bitmap_get_format (upload_bmp),
+                                          NULL, /* internal format */
+                                          &gl_format,
+                                          &gl_type);
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          internal_format,
+                                          &gl_intformat,
+                                          NULL,
+                                          NULL);
+
   tex_2d = _cogl_texture_2d_create_base (ctx,
                                          cogl_bitmap_get_width (bmp),
                                          cogl_bitmap_get_height (bmp),
@@ -180,10 +189,10 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
     {
       CoglError *ignore = NULL;
-      uint8_t *data = _cogl_bitmap_map (dst_bmp,
+      uint8_t *data = _cogl_bitmap_map (upload_bmp,
                                         COGL_BUFFER_ACCESS_READ, 0,
                                         &ignore);
-      CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
+      CoglPixelFormat format = cogl_bitmap_get_format (upload_bmp);
 
       tex_2d->first_pixel.gl_format = gl_format;
       tex_2d->first_pixel.gl_type = gl_type;
@@ -192,7 +201,7 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
         {
           memcpy (tex_2d->first_pixel.data, data,
                   _cogl_pixel_format_get_bytes_per_pixel (format));
-          _cogl_bitmap_unmap (dst_bmp);
+          _cogl_bitmap_unmap (upload_bmp);
         }
       else
         {
@@ -210,25 +219,24 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
                                           GL_TEXTURE_2D,
                                           tex_2d->gl_texture,
                                           FALSE,
-                                          dst_bmp,
+                                          upload_bmp,
                                           gl_intformat,
                                           gl_format,
                                           gl_type,
                                           error))
     {
-      cogl_object_unref (dst_bmp);
+      cogl_object_unref (upload_bmp);
       cogl_object_unref (tex_2d);
       return NULL;
     }
 
   tex_2d->gl_internal_format = gl_intformat;
 
-  cogl_object_unref (dst_bmp);
+  cogl_object_unref (upload_bmp);
 
   _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
 
   return tex_2d;
-
 }
 
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
@@ -555,29 +563,37 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2d);
   CoglContext *ctx = tex->context;
+  CoglBitmap *upload_bmp;
+  CoglPixelFormat upload_format;
   GLenum gl_format;
   GLenum gl_type;
   CoglBool status = TRUE;
 
-  bmp = _cogl_texture_prepare_for_upload (bmp,
-                                          cogl_texture_get_format (tex),
-                                          NULL,
-                                          NULL,
-                                          &gl_format,
-                                          &gl_type,
-                                          error);
-  if (!bmp)
+  upload_bmp =
+    _cogl_bitmap_convert_for_upload (bmp,
+                                     cogl_texture_get_format (tex),
+                                     FALSE, /* can't convert in place */
+                                     error);
+  if (upload_bmp == NULL)
     return FALSE;
 
+  upload_format = cogl_bitmap_get_format (upload_bmp);
+
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          upload_format,
+                                          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 &&
       !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
     {
       CoglError *ignore = NULL;
       uint8_t *data =
-        _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore);
+        _cogl_bitmap_map (upload_bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore);
       CoglPixelFormat bpp =
-        _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp));
+        _cogl_pixel_format_get_bytes_per_pixel (upload_format);
 
       tex_2d->first_pixel.gl_format = gl_format;
       tex_2d->first_pixel.gl_type = gl_type;
@@ -585,7 +601,9 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
       if (data)
         {
           memcpy (tex_2d->first_pixel.data,
-                  data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
+                  (data +
+                   cogl_bitmap_get_rowstride (upload_bmp) * src_y +
+                   bpp * src_x),
                   bpp);
           _cogl_bitmap_unmap (bmp);
         }
@@ -605,12 +623,12 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
                                                         dst_x, dst_y,
                                                         width, height,
                                                         level,
-                                                        bmp,
+                                                        upload_bmp,
                                                         gl_format,
                                                         gl_type,
                                                         error);
 
-  cogl_object_unref (bmp);
+  cogl_object_unref (upload_bmp);
 
   _cogl_texture_gl_maybe_update_max_level (tex, level);
 
diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h
index 1aa558a..f822a7f 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop-private.h
+++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h
@@ -51,6 +51,7 @@ _cogl_texture_2d_nop_allocate (CoglTexture *tex,
 CoglTexture2D *
 _cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
                                       CoglPixelFormat internal_format,
+                                      CoglBool can_convert_in_place,
                                       CoglError **error);
 
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c
index 5831e27..b63a7b7 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop.c
+++ b/cogl/driver/nop/cogl-texture-2d-nop.c
@@ -65,6 +65,7 @@ _cogl_texture_2d_nop_allocate (CoglTexture *tex,
 CoglTexture2D *
 _cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
                                       CoglPixelFormat internal_format,
+                                      CoglBool can_convert_in_place,
                                       CoglError **error)
 {
   return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
-- 
1.8.2.1



More information about the Cogl mailing list