cogl: Let GL do the format conversion when uploading texture data
authorNeil Roberts <neil@linux.intel.com>
Mon, 1 Feb 2010 12:11:58 +0000 (12:11 +0000)
committerNeil Roberts <neil@linux.intel.com>
Mon, 1 Feb 2010 13:27:34 +0000 (13:27 +0000)
Cogl accepts a pixel format for both the data in memory and the
internal format to be used for the texture. If they do not match then
it would convert them using the CoglBitmap functions before uploading
the data. However, GL also lets you specify both formats so it makes
more sense to let GL do the conversion. The driver may need the
texture in a specific format so it may end up being converted anyway.

The cogl_texture_upload_data functions have been removed and replaced
with a single function to prepare the bitmap. This will only do the
premultiplication conversion because that is the only part that GL
can't do directly.

clutter/cogl/cogl/cogl-atlas-texture.c
clutter/cogl/cogl/cogl-texture-2d-sliced.c
clutter/cogl/cogl/cogl-texture-2d.c
clutter/cogl/cogl/cogl-texture-private.h
clutter/cogl/cogl/cogl-texture.c

index efd8052..0c018f0 100644 (file)
@@ -508,11 +508,8 @@ _cogl_atlas_texture_set_region (CoglTexture    *tex,
     {
       gint             bpp;
       CoglBitmap       source_bmp;
-      CoglBitmap       temp_bmp;
-      gboolean         source_bmp_owner = FALSE;
-      CoglPixelFormat  closest_format;
-      GLenum           closest_gl_format;
-      GLenum           closest_gl_type;
+      CoglBitmap       tmp_bmp;
+      gboolean         tmp_bmp_owner = FALSE;
       gboolean         success;
 
       /* Check for valid format */
@@ -533,25 +530,14 @@ _cogl_atlas_texture_set_region (CoglTexture    *tex,
       bpp = _cogl_get_format_bpp (format);
       source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
 
-      /* Find closest format to internal that's supported by GL */
-      closest_format = _cogl_pixel_format_to_gl (atlas_tex->format,
-                                                 NULL, /* don't need */
-                                                 &closest_gl_format,
-                                                 &closest_gl_type);
-
-      /* If no direct match, convert */
-      if (closest_format != format)
-        {
-          /* Convert to required format */
-          success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
-                                                             &temp_bmp,
-                                                             closest_format);
-
-          /* Swap bitmaps if succeeded */
-          if (!success) return FALSE;
-          source_bmp = temp_bmp;
-          source_bmp_owner = TRUE;
-        }
+      /* Prepare the bitmap so that it will do the premultiplication
+         conversion */
+      _cogl_texture_prepare_for_upload (&source_bmp,
+                                        atlas_tex->format,
+                                        NULL,
+                                        &tmp_bmp,
+                                        &tmp_bmp_owner,
+                                        NULL, NULL, NULL);
 
       /* Upload the data ignoring the premult bit */
       success =
@@ -559,16 +545,16 @@ _cogl_atlas_texture_set_region (CoglTexture    *tex,
                                                     src_x, src_y,
                                                     dst_x, dst_y,
                                                     dst_width, dst_height,
-                                                    source_bmp.width,
-                                                    source_bmp.height,
-                                                    source_bmp.format &
+                                                    tmp_bmp.width,
+                                                    tmp_bmp.height,
+                                                    tmp_bmp.format &
                                                     ~COGL_PREMULT_BIT,
-                                                    source_bmp.rowstride,
-                                                    source_bmp.data);
+                                                    tmp_bmp.rowstride,
+                                                    tmp_bmp.data);
 
       /* Free data if owner */
-      if (source_bmp_owner)
-        g_free (source_bmp.data);
+      if (tmp_bmp_owner)
+        g_free (tmp_bmp.data);
 
       return success;
     }
@@ -927,9 +913,13 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
                                      CoglTextureFlags flags,
                                      CoglPixelFormat  internal_format)
 {
-  CoglAtlasTexture       *atlas_tex;
-  CoglBitmap             *bmp = (CoglBitmap *) bmp_handle;
-  CoglTextureUploadData   upload_data;
+  CoglAtlasTexture *atlas_tex;
+  CoglBitmap       *bmp = (CoglBitmap *) bmp_handle;
+  CoglBitmap        dst_bmp;
+  gboolean          dst_bmp_owner;
+  GLenum            gl_intformat;
+  GLenum            gl_format;
+  GLenum            gl_type;
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
@@ -956,18 +946,18 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
   if (!cogl_features_available (COGL_FEATURE_TEXTURE_READ_PIXELS))
     return COGL_INVALID_HANDLE;
 
-  upload_data.bitmap = *bmp;
-  upload_data.bitmap_owner = FALSE;
-
-  if (!_cogl_texture_upload_data_prepare_format (&upload_data,
-                                                 &internal_format))
-    {
-      _cogl_texture_upload_data_free (&upload_data);
-      return COGL_INVALID_HANDLE;
-    }
-
   COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp->width, bmp->height);
 
+  if (!_cogl_texture_prepare_for_upload (bmp,
+                                         internal_format,
+                                         &internal_format,
+                                         NULL,
+                                         NULL,
+                                         &gl_intformat,
+                                         &gl_format,
+                                         &gl_type))
+    return COGL_INVALID_HANDLE;
+
   /* If the texture is in a strange format then we can't use it */
   if (internal_format != COGL_PIXEL_FORMAT_RGB_888 &&
       (internal_format & ~COGL_PREMULT_BIT) != COGL_PIXEL_FORMAT_RGBA_8888)
@@ -975,7 +965,6 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
       COGL_NOTE (ATLAS, "Texture can not be added because the "
                  "format is unsupported");
 
-      _cogl_texture_upload_data_free (&upload_data);
       return COGL_INVALID_HANDLE;
     }
 
@@ -984,8 +973,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 = upload_data.bitmap.width + 2;
-  atlas_tex->rectangle.height = upload_data.bitmap.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,
@@ -993,15 +982,20 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
                                           atlas_tex->rectangle.height))
     {
       g_free (atlas_tex);
-      _cogl_texture_upload_data_free (&upload_data);
       return COGL_INVALID_HANDLE;
     }
 
-  if (!_cogl_texture_upload_data_convert (&upload_data, internal_format))
+  if (!_cogl_texture_prepare_for_upload (bmp,
+                                         internal_format,
+                                         &internal_format,
+                                         &dst_bmp,
+                                         &dst_bmp_owner,
+                                         &gl_intformat,
+                                         &gl_format,
+                                         &gl_type))
     {
       cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle);
       g_free (atlas_tex);
-      _cogl_texture_upload_data_free (&upload_data);
       return COGL_INVALID_HANDLE;
     }
 
@@ -1019,14 +1013,17 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle       bmp_handle,
   _cogl_atlas_texture_set_region_with_border (atlas_tex,
                                               0, 0,
                                               0, 0,
-                                              upload_data.bitmap.width,
-                                              upload_data.bitmap.height,
-                                              upload_data.bitmap.width,
-                                              upload_data.bitmap.height,
-                                              upload_data.bitmap.format &
+                                              dst_bmp.width,
+                                              dst_bmp.height,
+                                              dst_bmp.width,
+                                              dst_bmp.height,
+                                              dst_bmp.format &
                                               ~COGL_PREMULT_BIT,
-                                              upload_data.bitmap.rowstride,
-                                              upload_data.bitmap.data);
+                                              dst_bmp.rowstride,
+                                              dst_bmp.data);
+
+  if (dst_bmp_owner)
+    g_free (dst_bmp.data);
 
   return _cogl_atlas_texture_handle_new (atlas_tex);
 }
index 9716062..0cfef1f 100644 (file)
@@ -213,7 +213,10 @@ _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds,
 
 static gboolean
 _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
-                                      CoglTextureUploadData *upload_data)
+                                      CoglBitmap          *bmp,
+                                      GLenum               gl_intformat,
+                                      GLenum               gl_format,
+                                      GLenum               gl_type)
 {
   CoglSpan  *x_span;
   CoglSpan  *y_span;
@@ -222,11 +225,10 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
   gint               x,y;
   guchar            *waste_buf;
 
-  bpp = _cogl_get_format_bpp (upload_data->bitmap.format);
+  bpp = _cogl_get_format_bpp (bmp->format);
 
-  waste_buf =
-    _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
-                                                   upload_data->bitmap.format);
+  waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
+                                                             bmp->format);
 
   /* Iterate vertical slices */
   for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
@@ -252,27 +254,26 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
                                      0, /* dst y */
                                      x_span->size - x_span->waste, /* width */
                                      y_span->size - y_span->waste, /* height */
-                                     &upload_data->bitmap,
-                                     upload_data->gl_format,
-                                     upload_data->gl_type);
+                                     bmp,
+                                     gl_format,
+                                     gl_type);
 
           /* Keep a copy of the first pixel if needed */
           if (tex_2ds->first_pixels)
             {
               memcpy (tex_2ds->first_pixels[slice_num].data,
-                      upload_data->bitmap.data + x_span->start * bpp
-                      + y_span->start * upload_data->bitmap.rowstride,
+                      bmp->data + x_span->start * bpp
+                      + y_span->start * bmp->rowstride,
                       bpp);
-              tex_2ds->first_pixels[slice_num].gl_format =
-                upload_data->gl_format;
-              tex_2ds->first_pixels[slice_num].gl_type = upload_data->gl_type;
+              tex_2ds->first_pixels[slice_num].gl_format = gl_format;
+              tex_2ds->first_pixels[slice_num].gl_type = gl_type;
             }
 
           /* Fill the waste with a copies of the rightmost pixels */
           if (x_span->waste > 0)
             {
-              const guchar *src = upload_data->bitmap.data
-                + y_span->start * upload_data->bitmap.rowstride
+              const guchar *src = bmp->data
+                + y_span->start * bmp->rowstride
                 + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
               guchar *dst = waste_buf;
               guint wx, wy;
@@ -284,7 +285,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
                       memcpy (dst, src, bpp);
                       dst += bpp;
                     }
-                  src += upload_data->bitmap.rowstride;
+                  src += bmp->rowstride;
                 }
 
               _cogl_texture_driver_prep_gl_for_pixels_upload (
@@ -296,15 +297,15 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
                                    0,
                                    x_span->waste,
                                    y_span->size - y_span->waste,
-                                   upload_data->gl_format, upload_data->gl_type,
+                                   gl_format, gl_type,
                                    waste_buf) );
             }
 
           if (y_span->waste > 0)
             {
-              const guchar *src = upload_data->bitmap.data
+              const guchar *src = bmp->data
                 + ((y_span->start + y_span->size - y_span->waste - 1)
-                   * upload_data->bitmap.rowstride)
+                   * bmp->rowstride)
                 + x_span->start * bpp;
               guchar *dst = waste_buf;
               guint wy, wx;
@@ -330,7 +331,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
                                    y_span->size - y_span->waste,
                                    x_span->size,
                                    y_span->waste,
-                                   upload_data->gl_format, upload_data->gl_type,
+                                   gl_format, gl_type,
                                    waste_buf) );
             }
         }
@@ -685,7 +686,10 @@ _cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture *tex,
 
 static gboolean
 _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
-                                       const CoglTextureUploadData *upload_data)
+                                       gint width, gint height,
+                                       GLenum gl_intformat,
+                                       GLenum gl_format,
+                                       GLenum gl_type)
 {
   gint              max_width;
   gint              max_height;
@@ -703,15 +707,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
   /* Initialize size of largest slice according to supported features */
   if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
     {
-      max_width = upload_data->bitmap.width;
-      max_height = upload_data->bitmap.height;
+      max_width = width;
+      max_height = height;
       tex_2ds->gl_target  = GL_TEXTURE_2D;
       slices_for_size = _cogl_rect_slices_for_size;
     }
   else
     {
-      max_width = cogl_util_next_p2 (upload_data->bitmap.width);
-      max_height = cogl_util_next_p2 (upload_data->bitmap.height);
+      max_width = cogl_util_next_p2 (width);
+      max_height = cogl_util_next_p2 (height);
       tex_2ds->gl_target = GL_TEXTURE_2D;
       slices_for_size = _cogl_pot_slices_for_size;
     }
@@ -723,8 +727,8 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
 
       /* Check if size supported else bail out */
       if (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
-                                                upload_data->gl_intformat,
-                                                upload_data->gl_type,
+                                                gl_intformat,
+                                                gl_type,
                                                 max_width,
                                                 max_height))
         {
@@ -746,19 +750,19 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
       /* Add a single span for width and height */
       span.start = 0;
       span.size = max_width;
-      span.waste = max_width - upload_data->bitmap.width;
+      span.waste = max_width - width;
       g_array_append_val (tex_2ds->slice_x_spans, span);
 
       span.size = max_height;
-      span.waste = max_height - upload_data->bitmap.height;
+      span.waste = max_height - height;
       g_array_append_val (tex_2ds->slice_y_spans, span);
     }
   else
     {
       /* Decrease the size of largest slice until supported by GL */
       while (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
-                                                   upload_data->gl_intformat,
-                                                   upload_data->gl_type,
+                                                   gl_intformat,
+                                                   gl_type,
                                                    max_width,
                                                    max_height))
         {
@@ -773,11 +777,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
         }
 
       /* Determine the slices required to cover the bitmap area */
-      n_x_slices = slices_for_size (upload_data->bitmap.width,
+      n_x_slices = slices_for_size (width,
                                     max_width, tex_2ds->max_waste,
                                     NULL);
 
-      n_y_slices = slices_for_size (upload_data->bitmap.height,
+      n_y_slices = slices_for_size (height,
                                     max_height, tex_2ds->max_waste,
                                     NULL);
 
@@ -791,11 +795,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
                                                   n_y_slices);
 
       /* Fill span arrays with info */
-      slices_for_size (upload_data->bitmap.width,
+      slices_for_size (width,
                        max_width, tex_2ds->max_waste,
                        tex_2ds->slice_x_spans);
 
-      slices_for_size (upload_data->bitmap.height,
+      slices_for_size (height,
                        max_height, tex_2ds->max_waste,
                        tex_2ds->slice_y_spans);
     }
@@ -845,15 +849,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
           /* Setup texture parameters */
           GE( _cogl_texture_driver_bind (tex_2ds->gl_target,
                                          gl_handles[y * n_x_slices + x],
-                                         upload_data->gl_intformat) );
+                                         gl_intformat) );
 
           _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target,
                                                             transparent_color);
 
           /* Pass NULL data to init size and internal format */
-          GE( glTexImage2D (tex_2ds->gl_target, 0, upload_data->gl_intformat,
+          GE( glTexImage2D (tex_2ds->gl_target, 0, gl_intformat,
                             x_span->size, y_span->size, 0,
-                            upload_data->gl_format, upload_data->gl_type, 0) );
+                            gl_format, gl_type, 0) );
         }
     }
 
@@ -893,11 +897,14 @@ _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
 
 static gboolean
 _cogl_texture_2d_sliced_upload_from_data
-                                      (CoglTexture2DSliced   *tex_2ds,
-                                       CoglTextureUploadData *upload_data,
-                                       CoglPixelFormat        internal_format)
+                                      (CoglTexture2DSliced *tex_2ds,
+                                       CoglBitmap          *bmp,
+                                       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;
 
@@ -914,36 +921,72 @@ _cogl_texture_2d_sliced_upload_from_data
   tex_2ds->min_filter = GL_FALSE;
   tex_2ds->mag_filter = GL_FALSE;
 
-  if (upload_data->bitmap.data)
+  if (bmp->data)
     {
-      if (!_cogl_texture_upload_data_prepare (upload_data, internal_format))
+      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, upload_data))
-        return FALSE;
+      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
+                                                  bmp->width,
+                                                  bmp->height,
+                                                  gl_intformat,
+                                                  gl_format,
+                                                  gl_type))
+        {
+          if (dst_bmp_owner)
+            g_free (dst_bmp.data);
 
-      if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds, upload_data))
-        return FALSE;
+          return FALSE;
+        }
+
+      if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
+                                                 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 */
-      upload_data->bitmap.format =
-        _cogl_pixel_format_to_gl (internal_format,
-                                  &upload_data->gl_intformat,
-                                  &upload_data->gl_format,
-                                  &upload_data->gl_type);
+      _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, upload_data))
+      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
+                                                  bmp->width,
+                                                  bmp->height,
+                                                  gl_intformat,
+                                                  gl_format,
+                                                  gl_type))
         return FALSE;
     }
 
-  tex_2ds->gl_format = upload_data->gl_intformat;
-  tex_2ds->width = upload_data->bitmap.width;
-  tex_2ds->height = upload_data->bitmap.height;
-  tex_2ds->format = upload_data->bitmap.format;
+  tex_2ds->gl_format = gl_intformat;
+  tex_2ds->width = bmp->width;
+  tex_2ds->height = bmp->height;
+  tex_2ds->format = bmp->format;
 
   return TRUE;
 }
@@ -956,7 +999,7 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int     width,
 {
   CoglTexture2DSliced   *tex_2ds;
   CoglTexture           *tex;
-  CoglTextureUploadData  upload_data;
+  CoglBitmap             bmp;
 
   /* Since no data, we need some internal format */
   if (internal_format == COGL_PIXEL_FORMAT_ANY)
@@ -967,28 +1010,24 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int     width,
 
   tex = COGL_TEXTURE (tex_2ds);
 
-  upload_data.bitmap.width = width;
-  upload_data.bitmap.height = height;
-  upload_data.bitmap.data = NULL;
-  upload_data.bitmap_owner = FALSE;
+  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, &upload_data,
+  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &bmp,
                                                  internal_format))
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
-      _cogl_texture_upload_data_free (&upload_data);
       return COGL_INVALID_HANDLE;
     }
 
   tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
 
-  _cogl_texture_upload_data_free (&upload_data);
-
   return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 }
 
@@ -1000,7 +1039,6 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
   CoglTexture2DSliced   *tex_2ds;
   CoglTexture           *tex;
   CoglBitmap            *bmp = (CoglBitmap *)bmp_handle;
-  CoglTextureUploadData  upload_data;
 
   g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
 
@@ -1009,9 +1047,6 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
 
   tex = COGL_TEXTURE (tex_2ds);
 
-  upload_data.bitmap = *bmp;
-  upload_data.bitmap_owner = FALSE;
-
   if (flags & COGL_TEXTURE_NO_SLICING)
     tex_2ds->max_waste = -1;
   else
@@ -1025,18 +1060,15 @@ _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, &upload_data,
+  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, bmp,
                                                  internal_format))
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
-      _cogl_texture_upload_data_free (&upload_data);
       return COGL_INVALID_HANDLE;
     }
 
   tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
 
-  _cogl_texture_upload_data_free (&upload_data);
-
   return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 }
 
@@ -1398,12 +1430,10 @@ _cogl_texture_2d_sliced_set_region (CoglTexture    *tex,
   CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
   gint                 bpp;
   CoglBitmap           source_bmp;
-  CoglBitmap           temp_bmp;
-  gboolean             source_bmp_owner = FALSE;
-  CoglPixelFormat      closest_format;
+  CoglBitmap           tmp_bmp;
+  gboolean             tmp_bmp_owner = FALSE;
   GLenum               closest_gl_format;
   GLenum               closest_gl_type;
-  gboolean             success;
 
   /* Check for valid format */
   if (format == COGL_PIXEL_FORMAT_ANY)
@@ -1423,38 +1453,30 @@ _cogl_texture_2d_sliced_set_region (CoglTexture    *tex,
   bpp = _cogl_get_format_bpp (format);
   source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
 
-  /* Find closest format to internal that's supported by GL */
-  closest_format = _cogl_pixel_format_to_gl (tex_2ds->format,
-                                             NULL, /* don't need */
-                                             &closest_gl_format,
-                                             &closest_gl_type);
+  /* Prepare the bitmap so that it will do the premultiplication
+     conversion */
+  _cogl_texture_prepare_for_upload (&source_bmp,
+                                    tex_2ds->format,
+                                    NULL,
+                                    &tmp_bmp,
+                                    &tmp_bmp_owner,
+                                    NULL,
+                                    &closest_gl_format,
+                                    &closest_gl_type);
 
-  /* If no direct match, convert */
-  if (closest_format != format)
-    {
-      /* Convert to required format */
-      success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
-                                                         &temp_bmp,
-                                                         closest_format);
-
-      /* Swap bitmaps if succeeded */
-      if (!success) return FALSE;
-      source_bmp = temp_bmp;
-      source_bmp_owner = TRUE;
-    }
 
   /* Send data to GL */
   _cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
                                                   src_x, src_y,
                                                   dst_x, dst_y,
                                                   dst_width, dst_height,
-                                                  &source_bmp,
+                                                  &tmp_bmp,
                                                   closest_gl_format,
                                                   closest_gl_type);
 
   /* Free data if owner */
-  if (source_bmp_owner)
-    g_free (source_bmp.data);
+  if (tmp_bmp_owner)
+    g_free (tmp_bmp.data);
 
   return TRUE;
 }
index 8c8a31c..8d32e31 100644 (file)
@@ -275,42 +275,43 @@ _cogl_texture_2d_new_from_bitmap (CoglHandle       bmp_handle,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format)
 {
-  CoglTexture2D         *tex_2d;
-  CoglBitmap            *bmp = (CoglBitmap *)bmp_handle;
-  CoglTextureUploadData  upload_data;
+  CoglTexture2D *tex_2d;
+  CoglBitmap    *bmp = (CoglBitmap *)bmp_handle;
+  CoglBitmap     dst_bmp;
+  gboolean       dst_bmp_owner;
+  GLenum         gl_intformat;
+  GLenum         gl_format;
+  GLenum         gl_type;
 
   g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
 
-  upload_data.bitmap = *bmp;
-  upload_data.bitmap_owner = FALSE;
-
-  if (!_cogl_texture_upload_data_prepare_format (&upload_data,
-                                                 &internal_format) ||
-      !_cogl_texture_2d_can_create (upload_data.bitmap.width,
-                                    upload_data.bitmap.height,
-                                    internal_format) ||
-      !_cogl_texture_upload_data_convert (&upload_data, internal_format))
-    {
-      _cogl_texture_upload_data_free (&upload_data);
-      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))
+    return COGL_INVALID_HANDLE;
 
-  tex_2d = _cogl_texture_2d_create_base (upload_data.bitmap.width,
-                                         upload_data.bitmap.height,
+  tex_2d = _cogl_texture_2d_create_base (bmp->width,
+                                         bmp->height,
                                          flags,
-                                         upload_data.bitmap.format);
+                                         internal_format);
 
   GE( glGenTextures (1, &tex_2d->gl_texture) );
   _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D,
                                      tex_2d->gl_texture,
-                                     &upload_data.bitmap,
-                                     upload_data.gl_intformat,
-                                     upload_data.gl_format,
-                                     upload_data.gl_type);
+                                     &dst_bmp,
+                                     gl_intformat,
+                                     gl_format,
+                                     gl_type);
 
-  tex_2d->gl_format = upload_data.gl_intformat;
+  tex_2d->gl_format = gl_intformat;
 
-  _cogl_texture_upload_data_free (&upload_data);
+  if (dst_bmp_owner)
+    g_free (dst_bmp.data);
 
   return _cogl_texture_2d_handle_new (tex_2d);
 }
@@ -431,12 +432,10 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
   CoglTexture2D   *tex_2d = COGL_TEXTURE_2D (tex);
   gint             bpp;
   CoglBitmap       source_bmp;
-  CoglBitmap       temp_bmp;
-  gboolean         source_bmp_owner = FALSE;
-  CoglPixelFormat  closest_format;
+  CoglBitmap       tmp_bmp;
+  gboolean         tmp_bmp_owner = FALSE;
   GLenum           closest_gl_format;
   GLenum           closest_gl_type;
-  gboolean         success;
 
   /* Check for valid format */
   if (format == COGL_PIXEL_FORMAT_ANY)
@@ -456,25 +455,16 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
   bpp = _cogl_get_format_bpp (format);
   source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
 
-  /* Find closest format to internal that's supported by GL */
-  closest_format = _cogl_pixel_format_to_gl (tex_2d->format,
-                                             NULL, /* don't need */
-                                             &closest_gl_format,
-                                             &closest_gl_type);
-
-  /* If no direct match, convert */
-  if (closest_format != format)
-    {
-      /* Convert to required format */
-      success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
-                                                         &temp_bmp,
-                                                         closest_format);
-
-      /* Swap bitmaps if succeeded */
-      if (!success) return FALSE;
-      source_bmp = temp_bmp;
-      source_bmp_owner = TRUE;
-    }
+  /* Prepare the bitmap so that it will do the premultiplication
+     conversion */
+  _cogl_texture_prepare_for_upload (&source_bmp,
+                                    tex_2d->format,
+                                    NULL,
+                                    &tmp_bmp,
+                                    &tmp_bmp_owner,
+                                    NULL,
+                                    &closest_gl_format,
+                                    &closest_gl_type);
 
   /* Send data to GL */
   _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D,
@@ -482,13 +472,13 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
                                                src_x, src_y,
                                                dst_x, dst_y,
                                                dst_width, dst_height,
-                                               &source_bmp,
+                                               &tmp_bmp,
                                                closest_gl_format,
                                                closest_gl_type);
 
   /* Free data if owner */
-  if (source_bmp_owner)
-    g_free (source_bmp.data);
+  if (tmp_bmp_owner)
+    g_free (tmp_bmp.data);
 
   return TRUE;
 }
index e593743..857e3f6 100644 (file)
@@ -32,7 +32,6 @@
 
 typedef struct _CoglTexture           CoglTexture;
 typedef struct _CoglTextureVtable     CoglTextureVtable;
-typedef struct _CoglTextureUploadData CoglTextureUploadData;
 
 typedef void (*CoglTextureSliceCallback) (CoglHandle handle,
                                           GLuint gl_handle,
@@ -107,17 +106,6 @@ struct _CoglTextureVtable
   gint (* get_height) (CoglTexture *tex);
 };
 
-/* This represents the state needed to upload texture data. There are
-   utility functions in cogl-texture which use this state */
-struct _CoglTextureUploadData
-{
-  CoglBitmap bitmap;
-  gboolean   bitmap_owner;
-  GLenum     gl_intformat;
-  GLenum     gl_format;
-  GLenum     gl_type;
-};
-
 struct _CoglTexture
 {
   CoglHandleObject         _parent;
@@ -162,28 +150,20 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle);
 void
 _cogl_texture_ensure_non_quad_rendering (CoglHandle handle);
 
-/* Utility functions to help uploading a bitmap. These are intended to
- * be used by CoglTexture implementations or drivers... */
-
-void
-_cogl_texture_upload_data_free (CoglTextureUploadData *data);
-
-void
-_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data,
-                                       CoglBitmap            *new_bitmap);
-
-gboolean
-_cogl_texture_upload_data_prepare_format
-                                    (CoglTextureUploadData *data,
-                                     CoglPixelFormat       *internal_format);
-
-gboolean
-_cogl_texture_upload_data_convert (CoglTextureUploadData *data,
-                                   CoglPixelFormat internal_format);
+/* Utility function to help uploading a bitmap. If the bitmap needs
+   premult conversion then it will be copied and *copied_bitmap will
+   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
-_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
-                                   CoglPixelFormat        internal_format);
+_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);
 
 void
 _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride);
index fe349f7..7166e54 100644 (file)
@@ -100,25 +100,71 @@ cogl_texture_unref (CoglHandle handle)
   cogl_handle_unref (handle);
 }
 
-void
-_cogl_texture_upload_data_free (CoglTextureUploadData *data)
-{
-  if (data->bitmap.data != NULL && data->bitmap_owner)
-    g_free (data->bitmap.data);
+gboolean
+_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)
+{
+  /* If the application hasn't specified a specific format then we'll
+   * pick the most appropriate. By default Cogl will use a
+   * premultiplied internal format. Later we will add control over
+   * this. */
+  if (dst_format == COGL_PIXEL_FORMAT_ANY)
+    {
+      if ((src_bmp->format & COGL_A_BIT) &&
+          src_bmp->format != COGL_PIXEL_FORMAT_A_8)
+        dst_format = src_bmp->format | COGL_PREMULT_BIT;
+      else
+        dst_format = src_bmp->format;
+    }
 
-  data->bitmap.data = NULL;
-  data->bitmap_owner = FALSE;
-}
+  if (dst_bmp)
+    {
+      *copied_bitmap = FALSE;
+      *dst_bmp = *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 ((src_bmp->format & COGL_A_BIT) &&
+          src_bmp->format != COGL_PIXEL_FORMAT_A_8 &&
+          (src_bmp->format & COGL_PREMULT_BIT) !=
+          (dst_format & COGL_PREMULT_BIT))
+        {
+          dst_bmp->data = g_memdup (dst_bmp->data,
+                                    dst_bmp->height * dst_bmp->rowstride);
+          *copied_bitmap = TRUE;
 
-void
-_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data,
-                                       CoglBitmap            *new_bitmap)
-{
-  if (data->bitmap.data != NULL && data->bitmap_owner)
-    g_free (data->bitmap.data);
+          if (!_cogl_bitmap_convert_premult_status (dst_bmp,
+                                                    src_bmp->format ^
+                                                    COGL_PREMULT_BIT))
+            {
+              g_free (dst_bmp->data);
+              return FALSE;
+            }
+        }
+    }
+
+  /* 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,
+                            NULL, /* internal format */
+                            out_glformat,
+                            out_gltype);
+  _cogl_pixel_format_to_gl (dst_format,
+                            out_glintformat,
+                            NULL,
+                            NULL);
+
+  if (dst_format_out)
+    *dst_format_out = dst_format;
 
-  data->bitmap = *new_bitmap;
-  data->bitmap_owner = TRUE;
+  return TRUE;
 }
 
 void
@@ -157,64 +203,6 @@ _cogl_texture_set_wrap_mode_parameter (CoglHandle handle,
   tex->vtable->set_wrap_mode_parameter (tex, wrap_mode);
 }
 
-gboolean
-_cogl_texture_upload_data_prepare_format
-                                    (CoglTextureUploadData *data,
-                                     CoglPixelFormat       *internal_format)
-{
-  /* Was there any internal conversion requested?
-   * By default Cogl will use a premultiplied internal format. Later we will
-   * add control over this. */
-  if (*internal_format == COGL_PIXEL_FORMAT_ANY)
-    {
-      if ((data->bitmap.format & COGL_A_BIT) &&
-          data->bitmap.format != COGL_PIXEL_FORMAT_A_8)
-        *internal_format = data->bitmap.format | COGL_PREMULT_BIT;
-      else
-        *internal_format = data->bitmap.format;
-    }
-
-  /* Find closest format accepted by GL */
-  *internal_format = _cogl_pixel_format_to_gl (*internal_format,
-                                               &data->gl_intformat,
-                                               &data->gl_format,
-                                               &data->gl_type);
-
-  return TRUE;
-}
-
-gboolean
-_cogl_texture_upload_data_convert (CoglTextureUploadData *data,
-                                   CoglPixelFormat internal_format)
-{
-  CoglBitmap        new_bitmap;
-  gboolean          success;
-
-  /* Convert to internal format */
-  if (internal_format != data->bitmap.format)
-    {
-      success = _cogl_bitmap_convert_format_and_premult (&data->bitmap,
-                                                         &new_bitmap,
-                                                         internal_format);
-
-      if (!success)
-       return FALSE;
-
-      /* Update texture with new data */
-      _cogl_texture_upload_data_swap_bitmap (data, &new_bitmap);
-    }
-
-  return TRUE;
-}
-
-gboolean
-_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
-                                   CoglPixelFormat       internal_format)
-{
-  return (_cogl_texture_upload_data_prepare_format (data, &internal_format) &&
-          _cogl_texture_upload_data_convert (data, internal_format));
-}
-
 /* This is like CoglSpanIter except it deals with floats and it
    effectively assumes there is only one span from 0.0 to 1.0 */
 typedef struct _CoglTextureIter