diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index efd8052a5..0c018f056 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -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); } diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index 9716062d2..0cfef1f58 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -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; } diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index 8c8a31c5a..8d32e310e 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -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_prepare_for_upload (bmp, + internal_format, + &internal_format, + &dst_bmp, + &dst_bmp_owner, + &gl_intformat, + &gl_format, + &gl_type)) + return COGL_INVALID_HANDLE; - 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; - } - - 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; } diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index e59374334..857e3f6a8 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -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); +/* 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_format - (CoglTextureUploadData *data, - CoglPixelFormat *internal_format); - -gboolean -_cogl_texture_upload_data_convert (CoglTextureUploadData *data, - CoglPixelFormat internal_format); - -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); diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index fe349f725..7166e5406 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -100,25 +100,71 @@ cogl_texture_unref (CoglHandle handle) cogl_handle_unref (handle); } -void -_cogl_texture_upload_data_free (CoglTextureUploadData *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 (data->bitmap.data != NULL && data->bitmap_owner) - g_free (data->bitmap.data); + /* 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; -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 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; - data->bitmap = *new_bitmap; - data->bitmap_owner = TRUE; + 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; + + 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