diff --git a/cogl-pango/cogl-pango-display-list.c b/cogl-pango/cogl-pango-display-list.c index bc781f988..64012be1d 100644 --- a/cogl-pango/cogl-pango-display-list.c +++ b/cogl-pango/cogl-pango-display-list.c @@ -269,8 +269,9 @@ emit_vertex_buffer_geometry (CoglPangoDisplayListNode *node) n_verts = node->d.texture.rectangles->len * 4; buffer - = cogl_attribute_buffer_new (ctx, - n_verts * sizeof (CoglVertexP2T2), NULL); + = cogl_attribute_buffer_new_with_size (ctx, + n_verts * + sizeof (CoglVertexP2T2)); if ((verts = cogl_buffer_map (COGL_BUFFER (buffer), COGL_BUFFER_ACCESS_WRITE, diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl-atlas-texture-private.h index 451bd8387..7a70f544d 100644 --- a/cogl/cogl-atlas-texture-private.h +++ b/cogl/cogl-atlas-texture-private.h @@ -58,9 +58,10 @@ struct _CoglAtlasTexture }; CoglAtlasTexture * -_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, +_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, CoglTextureFlags flags, - CoglPixelFormat internal_format); + CoglPixelFormat internal_format, + CoglError **error); CoglAtlasTexture * _cogl_atlas_texture_new_with_size (unsigned int width, diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index 81a89f2e7..5489c7b0f 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -44,6 +44,7 @@ #include "cogl-atlas.h" #include "cogl1-context.h" #include "cogl-sub-texture.h" +#include "cogl-error-private.h" #include @@ -433,63 +434,69 @@ _cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex) static CoglBool _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglAtlas *atlas = atlas_tex->atlas; /* Copy the central data */ - if (!cogl_texture_set_region_from_bitmap (atlas->texture, - src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - dst_y + atlas_tex->rectangle.y + 1, - dst_width, - dst_height, - bmp)) + if (!_cogl_texture_set_region_from_bitmap (atlas->texture, + src_x, src_y, + dst_x + atlas_tex->rectangle.x + 1, + dst_y + atlas_tex->rectangle.y + 1, + dst_width, + dst_height, + bmp, + error)) return FALSE; /* Update the left edge pixels */ if (dst_x == 0 && - !cogl_texture_set_region_from_bitmap (atlas->texture, - src_x, src_y, - atlas_tex->rectangle.x, - dst_y + atlas_tex->rectangle.y + 1, - 1, dst_height, - bmp)) + !_cogl_texture_set_region_from_bitmap (atlas->texture, + src_x, src_y, + atlas_tex->rectangle.x, + dst_y + atlas_tex->rectangle.y + 1, + 1, dst_height, + bmp, + error)) return FALSE; /* Update the right edge pixels */ if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && - !cogl_texture_set_region_from_bitmap (atlas->texture, - src_x + dst_width - 1, src_y, - atlas_tex->rectangle.x + - atlas_tex->rectangle.width - 1, - dst_y + atlas_tex->rectangle.y + 1, - 1, dst_height, - bmp)) + !_cogl_texture_set_region_from_bitmap (atlas->texture, + src_x + dst_width - 1, src_y, + atlas_tex->rectangle.x + + atlas_tex->rectangle.width - 1, + dst_y + atlas_tex->rectangle.y + 1, + 1, dst_height, + bmp, + error)) return FALSE; /* Update the top edge pixels */ if (dst_y == 0 && - !cogl_texture_set_region_from_bitmap (atlas->texture, - src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - atlas_tex->rectangle.y, - dst_width, 1, - bmp)) + !_cogl_texture_set_region_from_bitmap (atlas->texture, + src_x, src_y, + dst_x + atlas_tex->rectangle.x + 1, + atlas_tex->rectangle.y, + dst_width, 1, + bmp, + error)) return FALSE; /* Update the bottom edge pixels */ if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && - !cogl_texture_set_region_from_bitmap (atlas->texture, - src_x, src_y + dst_height - 1, - dst_x + atlas_tex->rectangle.x + 1, - atlas_tex->rectangle.y + - atlas_tex->rectangle.height - 1, - dst_width, 1, - bmp)) + !_cogl_texture_set_region_from_bitmap (atlas->texture, + src_x, src_y + dst_height - 1, + dst_x + atlas_tex->rectangle.x + 1, + atlas_tex->rectangle.y + + atlas_tex->rectangle.height - 1, + dst_width, 1, + bmp, + error)) return FALSE; return TRUE; @@ -497,7 +504,8 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, static CoglBitmap * _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex, - CoglBitmap *bmp) + CoglBitmap *bmp, + CoglError **error) { CoglPixelFormat internal_format; CoglBitmap *converted_bmp; @@ -519,7 +527,8 @@ _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex, NULL, /* dst_format_out */ NULL, /* glintformat */ NULL, /* glformat */ - NULL /* gltype */); + NULL, /* gltype */ + error); if (converted_bmp == NULL) return NULL; @@ -542,14 +551,15 @@ _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex, } static CoglBool -_cogl_atlas_texture_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_atlas_texture_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); @@ -560,14 +570,18 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, CoglBool ret; bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex, - bmp); + bmp, + error); + if (!bmp) + return FALSE; /* Upload the data ignoring the premult bit */ ret = _cogl_atlas_texture_set_region_with_border (atlas_tex, src_x, src_y, dst_x, dst_y, dst_width, dst_height, - bmp); + bmp, + error); cogl_object_unref (bmp); @@ -575,11 +589,12 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, } else /* Otherwise we can just forward on to the sub texture */ - return cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - bmp); + return _cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + bmp, + error); } static CoglPixelFormat @@ -727,9 +742,10 @@ _cogl_atlas_texture_new_with_size (unsigned int width, } CoglAtlasTexture * -_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, +_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, CoglTextureFlags flags, - CoglPixelFormat internal_format) + CoglPixelFormat internal_format, + CoglError **error) { CoglAtlasTexture *atlas_tex; CoglBitmap *dst_bmp; @@ -750,11 +766,17 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, flags, internal_format); if (atlas_tex == NULL) - return NULL; + { + _cogl_set_error (error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Texture type not compatible with atlas"); + return NULL; + } dst_bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex, - bmp); - + bmp, + error); if (dst_bmp == NULL) { cogl_object_unref (atlas_tex); @@ -763,14 +785,20 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, /* Defer to set_region so that we can share the code for copying the edge pixels to the border. */ - _cogl_atlas_texture_set_region_with_border (atlas_tex, - 0, /* src_x */ - 0, /* src_y */ - 0, /* dst_x */ - 0, /* dst_y */ - bmp_width, /* dst_width */ - bmp_height, /* dst_height */ - dst_bmp); + if (!_cogl_atlas_texture_set_region_with_border (atlas_tex, + 0, /* src_x */ + 0, /* src_y */ + 0, /* dst_x */ + 0, /* dst_y */ + bmp_width, /* dst_width */ + bmp_height, /* dst_height */ + dst_bmp, + error)) + { + cogl_object_unref (dst_bmp); + cogl_object_unref (atlas_tex); + return NULL; + } cogl_object_unref (dst_bmp); diff --git a/cogl/cogl-attribute-buffer.c b/cogl/cogl-attribute-buffer.c index a122e968a..20c093de0 100644 --- a/cogl/cogl-attribute-buffer.c +++ b/cogl/cogl-attribute-buffer.c @@ -39,28 +39,50 @@ static void _cogl_attribute_buffer_free (CoglAttributeBuffer *array); COGL_BUFFER_DEFINE (AttributeBuffer, attribute_buffer); CoglAttributeBuffer * -cogl_attribute_buffer_new (CoglContext *context, - size_t bytes, - const void *data) +cogl_attribute_buffer_new_with_size (CoglContext *context, + size_t bytes) { - CoglAttributeBuffer *array = g_slice_new (CoglAttributeBuffer); + CoglAttributeBuffer *buffer = g_slice_new (CoglAttributeBuffer); /* parent's constructor */ - _cogl_buffer_initialize (COGL_BUFFER (array), + _cogl_buffer_initialize (COGL_BUFFER (buffer), context, bytes, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER, COGL_BUFFER_UPDATE_HINT_STATIC); - _cogl_attribute_buffer_object_new (array); + return _cogl_attribute_buffer_object_new (buffer); +} +CoglAttributeBuffer * +cogl_attribute_buffer_new (CoglContext *context, + size_t bytes, + const void *data) +{ + CoglAttributeBuffer *buffer; + + buffer = cogl_attribute_buffer_new_with_size (context, bytes); + + /* Note: to keep the common cases simple this API doesn't throw + * CoglErrors, so developers can assume this function never returns + * NULL and we will simply abort on error. + * + * Developers wanting to catch errors can use + * cogl_attribute_buffer_new_with_size() and catch errors when later + * calling cogl_buffer_set_data() or cogl_buffer_map(). + */ + + /* XXX: NB: for Cogl 2.0 we don't allow NULL data here but we can't + * break the api for 1.x and so we keep the check for now. */ if (data) - cogl_buffer_set_data (COGL_BUFFER (array), - 0, - data, - bytes); - return array; + _cogl_buffer_set_data (COGL_BUFFER (buffer), + 0, + data, + bytes, + NULL); + + return buffer; } static void diff --git a/cogl/cogl-attribute-buffer.h b/cogl/cogl-attribute-buffer.h index 7b593e542..3150e07ff 100644 --- a/cogl/cogl-attribute-buffer.h +++ b/cogl/cogl-attribute-buffer.h @@ -50,18 +50,57 @@ COGL_BEGIN_DECLS #define COGL_ATTRIBUTE_BUFFER(buffer) ((CoglAttributeBuffer *)(buffer)) +/** + * cogl_attribute_buffer_new_with_size: + * @context: A #CoglContext + * @bytes: The number of bytes to allocate for vertex attribute data. + * + * Describes a new #CoglAttributeBuffer of @size bytes to contain + * arrays of vertex attribute data. Afterwards data can be set using + * cogl_buffer_set_data() or by mapping it into the application's + * address space using cogl_buffer_map(). + * + * The underlying storage of this buffer isn't allocated by this + * function so that you have an opportunity to use the + * cogl_buffer_set_update_hint() and cogl_buffer_set_usage_hint() + * functions which may influence how the storage is allocated. The + * storage will be allocated once you upload data to the buffer. + * + * Note: You can assume this function always succeeds and won't return + * %NULL + * + * Return value: A newly allocated #CoglAttributeBuffer. Never %NULL. + * + * Stability: Unstable + */ +CoglAttributeBuffer * +cogl_attribute_buffer_new_with_size (CoglContext *context, + size_t bytes); + /** * cogl_attribute_buffer_new: * @context: A #CoglContext * @bytes: The number of bytes to allocate for vertex attribute data. * @data: An optional pointer to vertex data to upload immediately. * - * Declares a new #CoglAttributeBuffer of @size bytes to contain arrays of vertex - * attribute data. Once declared, data can be set using cogl_buffer_set_data() - * or by mapping it into the application's address space using cogl_buffer_map(). + * Describes a new #CoglAttributeBuffer of @size bytes to contain + * arrays of vertex attribute data and also uploads @size bytes read + * from @data to the new buffer. * - * If @data isn't %NULL then @size bytes will be read from @data and - * immediately copied into the new buffer. + * You should never pass a %NULL data pointer. + * + * This function does not report out-of-memory errors back to + * the caller by returning %NULL and so you can assume this function + * always succeeds. + * + * In the unlikely case that there is an out of memory problem + * then Cogl will abort the application with a message. If your + * application needs to gracefully handle out-of-memory errors then + * you can use cogl_attribute_buffer_new_with_size() and then + * explicitly catch errors with cogl_buffer_set_data() or + * cogl_buffer_map(). + * + * Return value: A newly allocated #CoglAttributeBuffer (never %NULL) * * Since: 1.4 * Stability: Unstable diff --git a/cogl/cogl-bitmap-conversion.c b/cogl/cogl-bitmap-conversion.c index ca611ee55..15500ab3e 100644 --- a/cogl/cogl-bitmap-conversion.c +++ b/cogl/cogl-bitmap-conversion.c @@ -348,7 +348,8 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format) CoglBool _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, - CoglBitmap *dst_bmp) + CoglBitmap *dst_bmp, + CoglError **error) { uint8_t *src_data; uint8_t *dst_data; @@ -388,19 +389,20 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, if (!_cogl_bitmap_copy_subregion (src_bmp, dst_bmp, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ - width, height)) + width, height, + error)) return FALSE; if (need_premult) { if ((dst_format & COGL_PREMULT_BIT)) { - if (!_cogl_bitmap_premult (dst_bmp)) + if (!_cogl_bitmap_premult (dst_bmp, error)) return FALSE; } else { - if (!_cogl_bitmap_unpremult (dst_bmp)) + if (!_cogl_bitmap_unpremult (dst_bmp, error)) return FALSE; } } @@ -408,12 +410,13 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, return TRUE; } - src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0); + src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (src_data == NULL) return FALSE; dst_data = _cogl_bitmap_map (dst_bmp, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + error); if (dst_data == NULL) { _cogl_bitmap_unmap (src_bmp); @@ -472,7 +475,8 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, CoglBitmap * _cogl_bitmap_convert (CoglBitmap *src_bmp, - CoglPixelFormat dst_format) + CoglPixelFormat dst_format, + CoglError **error) { CoglBitmap *dst_bmp; int width, height; @@ -486,7 +490,7 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp, width, height, dst_format); - if (!_cogl_bitmap_convert_into_bitmap (src_bmp, dst_bmp)) + if (!_cogl_bitmap_convert_into_bitmap (src_bmp, dst_bmp, error)) { cogl_object_unref (dst_bmp); return NULL; @@ -496,7 +500,8 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp, } CoglBool -_cogl_bitmap_unpremult (CoglBitmap *bmp) +_cogl_bitmap_unpremult (CoglBitmap *bmp, + CoglError **error) { uint8_t *p, *data; uint16_t *tmp_row; @@ -513,12 +518,13 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp) if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, - 0)) == NULL) + 0, + error)) == NULL) return FALSE; /* If we can't directly unpremult the data inline then we'll allocate a temporary row and unpack the data. This assumes if we - can fast premult then we can also fast unpremult */ + can fast premult then we can also fast unpremult */ if (_cogl_bitmap_can_fast_premult (format)) tmp_row = NULL; else @@ -562,7 +568,8 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp) } CoglBool -_cogl_bitmap_premult (CoglBitmap *bmp) +_cogl_bitmap_premult (CoglBitmap *bmp, + CoglError **error) { uint8_t *p, *data; uint16_t *tmp_row; @@ -579,7 +586,8 @@ _cogl_bitmap_premult (CoglBitmap *bmp) if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, - 0)) == NULL) + 0, + error)) == NULL) return FALSE; /* If we can't directly premult the data inline then we'll allocate diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h index 661046065..ac1fd4b13 100644 --- a/cogl/cogl-bitmap-private.h +++ b/cogl/cogl-bitmap-private.h @@ -100,11 +100,13 @@ _cogl_bitmap_new_shared (CoglBitmap *shared_bmp, CoglBitmap * _cogl_bitmap_convert (CoglBitmap *bmp, - CoglPixelFormat dst_format); + CoglPixelFormat dst_format, + CoglError **error); CoglBool _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, - CoglBitmap *dst_bmp); + CoglBitmap *dst_bmp, + CoglError **error); CoglBitmap * _cogl_bitmap_from_file (CoglContext *ctx, @@ -120,28 +122,33 @@ _cogl_android_bitmap_new_from_asset (CoglContext *ctx, #endif CoglBool -_cogl_bitmap_unpremult (CoglBitmap *dst_bmp); +_cogl_bitmap_unpremult (CoglBitmap *dst_bmp, + CoglError **error); CoglBool -_cogl_bitmap_premult (CoglBitmap *dst_bmp); +_cogl_bitmap_premult (CoglBitmap *dst_bmp, + CoglError **error); CoglBool -_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, - CoglPixelFormat dst_format); +_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, + CoglPixelFormat dst_format, + CoglError **error); CoglBool _cogl_bitmap_copy_subregion (CoglBitmap *src, CoglBitmap *dst, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height); + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglError **error); /* Creates a deep copy of the source bitmap */ CoglBitmap * -_cogl_bitmap_copy (CoglBitmap *src_bmp); +_cogl_bitmap_copy (CoglBitmap *src_bmp, + CoglError **error); CoglBool _cogl_bitmap_get_size_from_file (const char *filename, @@ -163,7 +170,8 @@ _cogl_bitmap_set_format (CoglBitmap *bitmap, uint8_t * _cogl_bitmap_map (CoglBitmap *bitmap, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); void _cogl_bitmap_unmap (CoglBitmap *bitmap); @@ -180,7 +188,8 @@ _cogl_bitmap_unmap (CoglBitmap *bitmap); uint8_t * _cogl_bitmap_gl_bind (CoglBitmap *bitmap, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); void _cogl_bitmap_gl_unbind (CoglBitmap *bitmap); diff --git a/cogl/cogl-bitmap.c b/cogl/cogl-bitmap.c index ff00020de..5114694d0 100644 --- a/cogl/cogl-bitmap.c +++ b/cogl/cogl-bitmap.c @@ -33,6 +33,7 @@ #include "cogl-pixel-buffer.h" #include "cogl-context-private.h" #include "cogl-buffer-gl-private.h" +#include "cogl-error-private.h" #include @@ -56,27 +57,29 @@ _cogl_bitmap_free (CoglBitmap *bmp) } CoglBool -_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, - CoglPixelFormat dst_format) +_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, + CoglPixelFormat dst_format, + CoglError **error) { /* Do we need to unpremultiply? */ if ((bmp->format & COGL_PREMULT_BIT) > 0 && (dst_format & COGL_PREMULT_BIT) == 0 && COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format)) - return _cogl_bitmap_unpremult (bmp); + return _cogl_bitmap_unpremult (bmp, error); /* Do we need to premultiply? */ if ((bmp->format & COGL_PREMULT_BIT) == 0 && COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (bmp->format) && (dst_format & COGL_PREMULT_BIT) > 0) /* Try premultiplying using imaging library */ - return _cogl_bitmap_premult (bmp); + return _cogl_bitmap_premult (bmp, error); return TRUE; } CoglBitmap * -_cogl_bitmap_copy (CoglBitmap *src_bmp) +_cogl_bitmap_copy (CoglBitmap *src_bmp, + CoglError **error) { CoglBitmap *dst_bmp; CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp); @@ -88,11 +91,16 @@ _cogl_bitmap_copy (CoglBitmap *src_bmp) width, height, src_format); - _cogl_bitmap_copy_subregion (src_bmp, - dst_bmp, - 0, 0, /* src_x/y */ - 0, 0, /* dst_x/y */ - width, height); + if (!_cogl_bitmap_copy_subregion (src_bmp, + dst_bmp, + 0, 0, /* src_x/y */ + 0, 0, /* dst_x/y */ + width, height, + error)) + { + cogl_object_unref (dst_bmp); + return NULL; + } return dst_bmp; } @@ -100,12 +108,13 @@ _cogl_bitmap_copy (CoglBitmap *src_bmp) CoglBool _cogl_bitmap_copy_subregion (CoglBitmap *src, CoglBitmap *dst, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height) + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglError **error) { uint8_t *srcdata; uint8_t *dstdata; @@ -114,19 +123,21 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src, CoglBool succeeded = FALSE; /* Intended only for fast copies when format is equal! */ - g_assert ((src->format & ~COGL_PREMULT_BIT) == - (dst->format & ~COGL_PREMULT_BIT)); + _COGL_RETURN_VAL_IF_FAIL ((src->format & ~COGL_PREMULT_BIT) == + (dst->format & ~COGL_PREMULT_BIT), + FALSE); bpp = _cogl_pixel_format_get_bytes_per_pixel (src->format); - if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0))) + if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0, error))) { - if ((dstdata = _cogl_bitmap_map (dst, COGL_BUFFER_ACCESS_WRITE, 0))) + if ((dstdata = + _cogl_bitmap_map (dst, COGL_BUFFER_ACCESS_WRITE, 0, error))) { srcdata += src_y * src->rowstride + src_x * bpp; dstdata += dst_y * dst->rowstride + dst_x * bpp; - for (line=0; linerowstride; @@ -271,17 +282,18 @@ cogl_bitmap_new_with_size (CoglContext *context, unsigned int rowstride; /* creating a buffer to store "any" format does not make sense */ - if (G_UNLIKELY (format == COGL_PIXEL_FORMAT_ANY)) - return NULL; + _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); /* for now we fallback to cogl_pixel_buffer_new, later, we could ask * libdrm a tiled buffer for instance */ rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); - pixel_buffer = cogl_pixel_buffer_new (context, height * rowstride, NULL); + pixel_buffer = + cogl_pixel_buffer_new (context, + height * rowstride, + NULL); /* data */ - if (G_UNLIKELY (pixel_buffer == NULL)) - return NULL; + _COGL_RETURN_VAL_IF_FAIL (pixel_buffer != NULL, NULL); bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer), format, @@ -359,19 +371,21 @@ cogl_bitmap_error_quark (void) uint8_t * _cogl_bitmap_map (CoglBitmap *bitmap, CoglBufferAccess access, - CoglBufferMapHint hints) + CoglBufferMapHint hints, + CoglError **error) { /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) - return _cogl_bitmap_map (bitmap->shared_bmp, access, hints); + return _cogl_bitmap_map (bitmap->shared_bmp, access, hints, error); g_assert (!bitmap->mapped); if (bitmap->buffer) { - uint8_t *data = cogl_buffer_map (bitmap->buffer, - access, - hints); + uint8_t *data = _cogl_buffer_map (bitmap->buffer, + access, + hints, + error); COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This " "usually means that some conversion on the pixel array is " @@ -414,21 +428,23 @@ _cogl_bitmap_unmap (CoglBitmap *bitmap) uint8_t * _cogl_bitmap_gl_bind (CoglBitmap *bitmap, CoglBufferAccess access, - CoglBufferMapHint hints) + CoglBufferMapHint hints, + CoglError **error) { uint8_t *ptr; + CoglError *internal_error = NULL; /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) - return _cogl_bitmap_gl_bind (bitmap->shared_bmp, access, hints); + return _cogl_bitmap_gl_bind (bitmap->shared_bmp, access, hints, error); - g_assert (!bitmap->bound); + _COGL_RETURN_VAL_IF_FAIL (!bitmap->bound, NULL); /* If the bitmap wasn't created from a buffer then the implementation of bind is the same as map */ if (bitmap->buffer == NULL) { - uint8_t *data = _cogl_bitmap_map (bitmap, access, hints); + uint8_t *data = _cogl_bitmap_map (bitmap, access, hints, error); if (data) bitmap->bound = TRUE; return data; @@ -438,15 +454,29 @@ _cogl_bitmap_gl_bind (CoglBitmap *bitmap, if (access == COGL_BUFFER_ACCESS_READ) ptr = _cogl_buffer_gl_bind (bitmap->buffer, - COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK); + COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, + &internal_error); else if (access == COGL_BUFFER_ACCESS_WRITE) ptr = _cogl_buffer_gl_bind (bitmap->buffer, - COGL_BUFFER_BIND_TARGET_PIXEL_PACK); + COGL_BUFFER_BIND_TARGET_PIXEL_PACK, + &internal_error); else - g_assert_not_reached (); + { + ptr = NULL; + g_assert_not_reached (); + } + + /* NB: _cogl_buffer_gl_bind() may return NULL in non-error + * conditions so we have to explicitly check internal_error to see + * if an exception was thrown */ + if (internal_error) + { + _cogl_propogate_error (error, internal_error); + return NULL; + } /* The data pointer actually stores the offset */ - return GPOINTER_TO_INT (bitmap->data) + ptr; + return ptr + GPOINTER_TO_INT (bitmap->data); } void diff --git a/cogl/cogl-blit.c b/cogl/cogl-blit.c index 50bdf9aef..6d005fedb 100644 --- a/cogl/cogl-blit.c +++ b/cogl/cogl-blit.c @@ -292,6 +292,7 @@ _cogl_blit_get_tex_data_blit (CoglBlitData *data, data->format, data->src_width * data->bpp, data->image_data); + /* TODO: support chaining up errors during the blit */ } static void diff --git a/cogl/cogl-buffer-private.h b/cogl/cogl-buffer-private.h index 07a149044..014eae98a 100644 --- a/cogl/cogl-buffer-private.h +++ b/cogl/cogl-buffer-private.h @@ -45,14 +45,16 @@ struct _CoglBufferVtable size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); void (* unmap) (CoglBuffer *buffer); - CoglBool (* set_data) (CoglBuffer *buffer, - unsigned int offset, - const void *data, - unsigned int size); + CoglBool (* set_data) (CoglBuffer *buffer, + unsigned int offset, + const void *data, + unsigned int size, + CoglError **error); }; typedef enum _CoglBufferFlags @@ -137,6 +139,19 @@ _cogl_buffer_immutable_ref (CoglBuffer *buffer); void _cogl_buffer_immutable_unref (CoglBuffer *buffer); +CoglBool +_cogl_buffer_set_data (CoglBuffer *buffer, + size_t offset, + const void *data, + size_t size, + CoglError **error); + +void * +_cogl_buffer_map (CoglBuffer *buffer, + CoglBufferAccess access, + CoglBufferMapHint hints, + CoglError **error); + /* This is a wrapper around cogl_buffer_map_range for internal use when we want to map the buffer for write only to replace the entire contents. If the map fails then it will fallback to writing to a diff --git a/cogl/cogl-buffer.c b/cogl/cogl-buffer.c index 72fd3f852..2a6a7b1f7 100644 --- a/cogl/cogl-buffer.c +++ b/cogl/cogl-buffer.c @@ -83,7 +83,8 @@ malloc_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints) + CoglBufferMapHint hints, + CoglError **error) { buffer->flags |= COGL_BUFFER_FLAG_MAPPED; return buffer->data + offset; @@ -96,10 +97,11 @@ malloc_unmap (CoglBuffer *buffer) } static CoglBool -malloc_set_data (CoglBuffer *buffer, - unsigned int offset, - const void *data, - unsigned int size) +malloc_set_data (CoglBuffer *buffer, + unsigned int offset, + const void *data, + unsigned int size, + CoglError **error) { memcpy (buffer->data + offset, data, size); return TRUE; @@ -214,13 +216,28 @@ warn_about_midscene_changes (void) } void * -cogl_buffer_map (CoglBuffer *buffer, - CoglBufferAccess access, - CoglBufferMapHint hints) +_cogl_buffer_map (CoglBuffer *buffer, + CoglBufferAccess access, + CoglBufferMapHint hints, + CoglError **error) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); - return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints); + return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints, error); +} + +void * +cogl_buffer_map (CoglBuffer *buffer, + CoglBufferAccess access, + CoglBufferMapHint hints) +{ + CoglError *ignore_error = NULL; + void *ptr = + cogl_buffer_map_range (buffer, 0, buffer->size, access, hints, + &ignore_error); + if (!ptr) + cogl_error_free (ignore_error); + return ptr; } void * @@ -228,21 +245,21 @@ cogl_buffer_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints) + CoglBufferMapHint hints, + CoglError **error) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); + _COGL_RETURN_VAL_IF_FAIL (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED), NULL); if (G_UNLIKELY (buffer->immutable_ref)) warn_about_midscene_changes (); - if (buffer->flags & COGL_BUFFER_FLAG_MAPPED) - return buffer->data; - buffer->data = buffer->vtable.map_range (buffer, offset, size, access, - hints); + hints, + error); return buffer->data; } @@ -272,6 +289,7 @@ _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer, { CoglContext *ctx = buffer->context; void *ret; + CoglError *ignore_error = NULL; _COGL_RETURN_VAL_IF_FAIL (!ctx->buffer_map_fallback_in_use, NULL); @@ -281,23 +299,24 @@ _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer, offset, size, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + &ignore_error); if (ret) return ret; - else - { - /* If the map fails then we'll use a temporary buffer to fill - the data and then upload it using cogl_buffer_set_data when - the buffer is unmapped. The temporary buffer is shared to - avoid reallocating it every time */ - g_byte_array_set_size (ctx->buffer_map_fallback_array, size); - ctx->buffer_map_fallback_offset = offset; - buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK; + cogl_error_free (ignore_error); - return ctx->buffer_map_fallback_array->data; - } + /* If the map fails then we'll use a temporary buffer to fill + the data and then upload it using cogl_buffer_set_data when + the buffer is unmapped. The temporary buffer is shared to + avoid reallocating it every time */ + g_byte_array_set_size (ctx->buffer_map_fallback_array, size); + ctx->buffer_map_fallback_offset = offset; + + buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK; + + return ctx->buffer_map_fallback_array->data; } void @@ -311,29 +330,59 @@ _cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer) if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK)) { - cogl_buffer_set_data (buffer, - ctx->buffer_map_fallback_offset, - ctx->buffer_map_fallback_array->data, - ctx->buffer_map_fallback_array->len); + /* Note: don't try to catch OOM errors here since the use cases + * we currently have for this api (the journal and path stroke + * tesselator) don't have anything particularly sensible they + * can do in response to a failure anyway so it seems better to + * simply abort instead. + * + * If we find this is a problem for real world applications + * then in the path tesselation case we could potentially add an + * explicit cogl_path_tesselate_stroke() api that can throw an + * error for the app to cache. For the journal we could + * potentially flush the journal in smaller batches so we use + * smaller buffers, though that would probably not help for + * deferred renderers. + */ + _cogl_buffer_set_data (buffer, + ctx->buffer_map_fallback_offset, + ctx->buffer_map_fallback_array->data, + ctx->buffer_map_fallback_array->len, + NULL); buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK; } else cogl_buffer_unmap (buffer); } +CoglBool +_cogl_buffer_set_data (CoglBuffer *buffer, + size_t offset, + const void *data, + size_t size, + CoglError **error) +{ + _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), FALSE); + _COGL_RETURN_VAL_IF_FAIL ((offset + size) <= buffer->size, FALSE); + + if (G_UNLIKELY (buffer->immutable_ref)) + warn_about_midscene_changes (); + + return buffer->vtable.set_data (buffer, offset, data, size, error); +} + CoglBool cogl_buffer_set_data (CoglBuffer *buffer, size_t offset, const void *data, size_t size) { - _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), FALSE); - _COGL_RETURN_VAL_IF_FAIL ((offset + size) <= buffer->size, FALSE); - - if (G_UNLIKELY (buffer->immutable_ref)) - warn_about_midscene_changes (); - - return buffer->vtable.set_data (buffer, offset, data, size); + CoglError *ignore_error = NULL; + CoglBool status = + _cogl_buffer_set_data (buffer, offset, data, size, &ignore_error); + if (!status) + cogl_error_free (ignore_error); + return status; } CoglBuffer * diff --git a/cogl/cogl-buffer.h b/cogl/cogl-buffer.h index 54c15af6b..8db42a72f 100644 --- a/cogl/cogl-buffer.h +++ b/cogl/cogl-buffer.h @@ -33,6 +33,7 @@ #define __COGL_BUFFER_H__ #include +#include COGL_BEGIN_DECLS @@ -62,6 +63,25 @@ COGL_BEGIN_DECLS typedef struct _CoglBuffer CoglBuffer; +#define COGL_BUFFER_ERROR (_cogl_buffer_error_domain ()) + +/** + * CoglBufferError: + * @COGL_BUFFER_ERROR_MAP: A buffer could not be mapped either + * because the feature isn't supported or because a system + * limitation was hit. + * + * Error enumeration for #CoglBuffer + * + * Stability: unstable + */ +typedef enum { /*< prefix=COGL_BUFFER_ERROR >*/ + COGL_BUFFER_ERROR_MAP, +} CoglBufferError; + +uint32_t +_cogl_buffer_error_domain (void); + /** * cogl_is_buffer: * @object: a buffer object @@ -207,9 +227,9 @@ typedef enum { /*< prefix=COGL_BUFFER_MAP_HINT >*/ * Stability: unstable */ void * -cogl_buffer_map (CoglBuffer *buffer, - CoglBufferAccess access, - CoglBufferMapHint hints); +cogl_buffer_map (CoglBuffer *buffer, + CoglBufferAccess access, + CoglBufferMapHint hints); /** * cogl_buffer_map_range: @@ -219,6 +239,7 @@ cogl_buffer_map (CoglBuffer *buffer, * @access: how the mapped buffer will be used by the application * @hints: A mask of #CoglBufferMapHints that tell Cogl how * the data will be modified once mapped. + * @error: A #CoglError for catching exceptional errors * * Maps a sub-region of the buffer into the application's address space * for direct access. @@ -246,7 +267,8 @@ cogl_buffer_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); /** * cogl_buffer_unmap: diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h index 36f4c7adf..6bfdcd6b0 100644 --- a/cogl/cogl-driver.h +++ b/cogl/cogl-driver.h @@ -190,8 +190,11 @@ struct _CoglDriverVtable /* Initialize the specified region of storage of the given texture * with the contents of the specified bitmap region + * + * Since this may need to create the underlying storage first + * it may throw a NO_MEMORY error. */ - void + CoglBool (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d, CoglBitmap *bitmap, int dst_x, @@ -199,7 +202,8 @@ struct _CoglDriverVtable int src_x, int src_y, int width, - int height); + int height, + CoglError **error); /* Reads back the full contents of the given texture and write it to * @data in the given @format and with the given @rowstride. @@ -244,7 +248,8 @@ struct _CoglDriverVtable size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); /* Unmaps a buffer */ void @@ -256,7 +261,8 @@ struct _CoglDriverVtable (* buffer_set_data) (CoglBuffer *buffer, unsigned int offset, const void *data, - unsigned int size); + unsigned int size, + CoglError **error); }; #endif /* __COGL_DRIVER_H */ diff --git a/cogl/cogl-error-private.h b/cogl/cogl-error-private.h index 85b64f7f3..8842c5dfc 100644 --- a/cogl/cogl-error-private.h +++ b/cogl/cogl-error-private.h @@ -39,6 +39,10 @@ _cogl_set_error_literal (CoglError **error, int code, const char *message); +void +_cogl_propogate_error (CoglError **dest, + CoglError *src); + void _cogl_propogate_gerror (CoglError **dest, GError *src); diff --git a/cogl/cogl-error.c b/cogl/cogl-error.c index 969c85c0d..78ad14cd3 100644 --- a/cogl/cogl-error.c +++ b/cogl/cogl-error.c @@ -99,11 +99,18 @@ _cogl_set_error_literal (CoglError **error, } void -_cogl_propogate_gerror (CoglError **dest, - GError *src) +_cogl_propogate_error (CoglError **dest, + CoglError *src) { _COGL_RETURN_IF_FAIL (src != NULL); _cogl_set_error_literal (dest, src->domain, src->code, src->message); - g_error_free (src); + cogl_error_free (src); +} + +void +_cogl_propogate_gerror (CoglError **dest, + GError *src) +{ + _cogl_propogate_error (dest, (CoglError *)src); } diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index 8db49eccc..c9f8dd387 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -453,5 +453,12 @@ _cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer) return projection_stack->last_entry; } +CoglBool +_cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, + int x, + int y, + CoglReadPixelsFlags source, + CoglBitmap *bitmap, + CoglError **error); #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */ diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 19f9cd57f..81c4b2ee0 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -1333,6 +1333,7 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, y < framebuffer->clear_clip_y1) { uint8_t *pixel; + CoglError *ignore_error = NULL; /* we currently only care about cases where the premultiplied or * unpremultipled colors are equivalent... */ @@ -1341,9 +1342,13 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, pixel = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + &ignore_error); if (pixel == NULL) - return FALSE; + { + cogl_error_free (ignore_error); + return FALSE; + } pixel[0] = framebuffer->clear_color_red * 255.0; pixel[1] = framebuffer->clear_color_green * 255.0; @@ -1363,7 +1368,8 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, - CoglBitmap *bitmap) + CoglBitmap *bitmap, + CoglError **error) { CoglContext *ctx; CoglPixelFormat format; @@ -1371,6 +1377,8 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer, int width; int height; CoglBool res; + uint8_t *dst; + const uint8_t *src; _COGL_RETURN_VAL_IF_FAIL (source & COGL_READ_PIXELS_COLOR_BUFFER, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE); @@ -1382,79 +1390,79 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer, format = cogl_bitmap_get_format (bitmap); pbo = cogl_bitmap_new_with_size (ctx, width, height, format); - if (pbo == NULL) - return FALSE; /* Read into the pbo. We need to disable the flipping because the blit fast path in the driver does not work with GL_PACK_INVERT_MESA is set */ - res = cogl_framebuffer_read_pixels_into_bitmap (framebuffer, - x, y, - source | - COGL_READ_PIXELS_NO_FLIP, - pbo); - - if (res) + res = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + x, y, + source | + COGL_READ_PIXELS_NO_FLIP, + pbo, + error); + if (!res) { - uint8_t *dst; - - /* Copy the pixels back into application's buffer */ - dst = _cogl_bitmap_map (bitmap, - COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); - - if (dst == NULL) - res = FALSE; - else - { - const uint8_t *src; - - src = _cogl_bitmap_map (pbo, - COGL_BUFFER_ACCESS_READ, - 0 /* hints */); - if (src == NULL) - res = FALSE; - else - { - int src_rowstride = cogl_bitmap_get_rowstride (pbo); - int dst_rowstride = cogl_bitmap_get_rowstride (bitmap); - int to_copy = - _cogl_pixel_format_get_bytes_per_pixel (format) * width; - int y; - - /* If the framebuffer is onscreen we need to flip the - data while copying */ - if (!cogl_is_offscreen (framebuffer)) - { - src += src_rowstride * (height - 1); - src_rowstride = -src_rowstride; - } - - for (y = 0; y < height; y++) - { - memcpy (dst, src, to_copy); - dst += dst_rowstride; - src += src_rowstride; - } - - _cogl_bitmap_unmap (pbo); - } - - _cogl_bitmap_unmap (bitmap); - } + cogl_object_unref (pbo); + return FALSE; } + /* Copy the pixels back into application's buffer */ + dst = _cogl_bitmap_map (bitmap, + COGL_BUFFER_ACCESS_WRITE, + COGL_BUFFER_MAP_HINT_DISCARD, + error); + if (!dst) + { + cogl_object_unref (pbo); + return FALSE; + } + + src = _cogl_bitmap_map (pbo, + COGL_BUFFER_ACCESS_READ, + 0, /* hints */ + error); + if (src) + { + int src_rowstride = cogl_bitmap_get_rowstride (pbo); + int dst_rowstride = cogl_bitmap_get_rowstride (bitmap); + int to_copy = + _cogl_pixel_format_get_bytes_per_pixel (format) * width; + int y; + + /* If the framebuffer is onscreen we need to flip the + data while copying */ + if (!cogl_is_offscreen (framebuffer)) + { + src += src_rowstride * (height - 1); + src_rowstride = -src_rowstride; + } + + for (y = 0; y < height; y++) + { + memcpy (dst, src, to_copy); + dst += dst_rowstride; + src += src_rowstride; + } + + _cogl_bitmap_unmap (pbo); + } + else + res = FALSE; + + _cogl_bitmap_unmap (bitmap); + cogl_object_unref (pbo); return res; } CoglBool -cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, - int x, - int y, - CoglReadPixelsFlags source, - CoglBitmap *bitmap) +_cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, + int x, + int y, + CoglReadPixelsFlags source, + CoglBitmap *bitmap, + CoglError **error) { CoglContext *ctx; int framebuffer_height; @@ -1466,11 +1474,13 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, CoglBool pack_invert_set; int width; int height; + int status = FALSE; + CoglError *ignore_error = NULL; _COGL_RETURN_VAL_IF_FAIL (source & COGL_READ_PIXELS_COLOR_BUFFER, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE); - if (!cogl_framebuffer_allocate (framebuffer, NULL)) + if (!cogl_framebuffer_allocate (framebuffer, error)) return FALSE; ctx = cogl_framebuffer_get_context (framebuffer); @@ -1515,10 +1525,17 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, (width > 8 || height > 8) && (format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 && cogl_bitmap_get_buffer (bitmap) == NULL) - return _cogl_framebuffer_slow_read_pixels_workaround (framebuffer, - x, y, - source, - bitmap); + { + + if (_cogl_framebuffer_slow_read_pixels_workaround (framebuffer, + x, y, + source, + bitmap, + &ignore_error)) + return TRUE; + else + cogl_error_free (ignore_error); + } /* make sure any batched primitives get emitted to the GL driver * before issuing our read pixels... @@ -1578,7 +1595,7 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, CoglPixelFormat read_format; int bpp, rowstride; uint8_t *tmp_data; - int succeeded; + CoglBool succeeded; if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT)) @@ -1605,9 +1622,13 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, width, bpp); + /* Note: we don't worry about catching errors here since we know + * we won't be lazily allocating storage for this buffer so it + * won't fail due to lack of memory. */ tmp_data = _cogl_bitmap_gl_bind (tmp_bmp, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + NULL); GE( ctx, glReadPixels (x, y, width, height, gl_format, gl_type, @@ -1615,12 +1636,12 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, _cogl_bitmap_gl_unbind (tmp_bmp); - succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap); + succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap, error); cogl_object_unref (tmp_bmp); if (!succeeded) - return FALSE; + goto EXIT; } else { @@ -1629,6 +1650,7 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int bpp, rowstride; CoglBool succeeded = FALSE; uint8_t *pixels; + CoglError *internal_error = NULL; rowstride = cogl_bitmap_get_rowstride (bitmap); @@ -1658,7 +1680,17 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, pixels = _cogl_bitmap_gl_bind (shared_bmp, COGL_BUFFER_ACCESS_WRITE, - 0 /* hints */); + 0, /* hints */ + &internal_error); + /* NB: _cogl_bitmap_gl_bind() can return NULL in sucessfull + * cases so we have to explicitly check the cogl error pointer + * to know if there was a problem */ + if (internal_error) + { + cogl_object_unref (shared_bmp); + _cogl_propogate_error (error, internal_error); + goto EXIT; + } GE( ctx, glReadPixels (x, y, width, height, @@ -1670,21 +1702,15 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, /* Convert to the premult format specified by the caller in-place. This will do nothing if the premult status is already correct. */ - if (_cogl_bitmap_convert_premult_status (shared_bmp, format)) + if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error)) succeeded = TRUE; cogl_object_unref (shared_bmp); if (!succeeded) - return FALSE; + goto EXIT; } - /* Currently this function owns the pack_invert state and we don't want this - * to interfere with other Cogl components so all other code can assume that - * we leave the pack_invert state off. */ - if (pack_invert_set) - GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE)); - /* NB: All offscreen rendering is done upside down so there is no need * to flip in this case... */ if (!cogl_is_offscreen (framebuffer) && @@ -1699,10 +1725,11 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, pixels = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, - 0 /* hints */); + 0, /* hints */ + error); if (pixels == NULL) - return FALSE; + goto EXIT; temprow = g_alloca (rowstride * sizeof (uint8_t)); @@ -1724,7 +1751,34 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, _cogl_bitmap_unmap (bitmap); } - return TRUE; + status = TRUE; + +EXIT: + + /* Currently this function owns the pack_invert state and we don't want this + * to interfere with other Cogl components so all other code can assume that + * we leave the pack_invert state off. */ + if (pack_invert_set) + GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE)); + + return status; +} + +CoglBool +cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, + int x, + int y, + CoglReadPixelsFlags source, + CoglBitmap *bitmap) +{ + CoglError *ignore_error = NULL; + CoglBool status = + _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + x, y, source, bitmap, + &ignore_error); + if (!status) + cogl_error_free (ignore_error); + return status; } CoglBool @@ -1745,10 +1799,17 @@ cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer, format, bpp * width, /* rowstride */ pixels); - ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer, - x, y, - COGL_READ_PIXELS_COLOR_BUFFER, - bitmap); + + /* Note: we don't try and catch errors here since we created the + * bitmap storage up-front and can assume we wont hit an + * out-of-memory error which should be the only exception + * this api throws. + */ + ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + x, y, + COGL_READ_PIXELS_COLOR_BUFFER, + bitmap, + NULL); cogl_object_unref (bitmap); return ret; @@ -2378,8 +2439,9 @@ get_wire_line_indices (CoglContext *ctx, if (user_indices) { index_buffer = cogl_indices_get_buffer (user_indices); - indices = cogl_buffer_map (COGL_BUFFER (index_buffer), - COGL_BUFFER_ACCESS_READ, 0); + indices = _cogl_buffer_map (COGL_BUFFER (index_buffer), + COGL_BUFFER_ACCESS_READ, 0, + NULL); indices_type = cogl_indices_get_type (user_indices); } else diff --git a/cogl/cogl-indices.c b/cogl/cogl-indices.c index a018559f3..ebdaccf17 100644 --- a/cogl/cogl-indices.c +++ b/cogl/cogl-indices.c @@ -85,11 +85,19 @@ cogl_indices_new (CoglContext *context, CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes); CoglBuffer *buffer = COGL_BUFFER (index_buffer); CoglIndices *indices; + CoglError *ignore_error = NULL; - cogl_buffer_set_data (buffer, - 0, - indices_data, - buffer_bytes); + _cogl_buffer_set_data (buffer, + 0, + indices_data, + buffer_bytes, + &ignore_error); + if (ignore_error) + { + cogl_error_free (ignore_error); + cogl_object_unref (index_buffer); + return NULL; + } indices = cogl_indices_new_for_buffer (type, index_buffer, 0); cogl_object_unref (index_buffer); diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index a16c227c8..6e39725b3 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -658,8 +658,9 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start, /* Mapping a buffer for read is probably a really bad thing to do but this will only happen during debugging so it probably doesn't matter */ - verts = ((uint8_t *)cogl_buffer_map (COGL_BUFFER (state->attribute_buffer), - COGL_BUFFER_ACCESS_READ, 0) + + verts = ((uint8_t *)_cogl_buffer_map (COGL_BUFFER (state->attribute_buffer), + COGL_BUFFER_ACCESS_READ, 0, + NULL) + state->array_offset); _cogl_journal_dump_quad_batch (verts, @@ -1065,14 +1066,14 @@ create_attribute_buffer (CoglJournal *journal, if (vbo == NULL) { - vbo = cogl_attribute_buffer_new (ctx, n_bytes, NULL); + vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes); journal->vbo_pool[journal->next_vbo_in_pool] = vbo; } else if (cogl_buffer_get_size (COGL_BUFFER (vbo)) < n_bytes) { /* If the buffer is too small then we'll just recreate it */ cogl_object_unref (vbo); - vbo = cogl_attribute_buffer_new (ctx, n_bytes, NULL); + vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes); journal->vbo_pool[journal->next_vbo_in_pool] = vbo; } @@ -1718,11 +1719,10 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, CoglBitmap *bitmap, CoglBool *found_intersection) { + CoglContext *ctx; CoglPixelFormat format; int i; - _COGL_GET_CONTEXT (ctx, FALSE); - /* XXX: this number has been plucked out of thin air, but the idea * is that if so many pixels are being read from the same un-changed * journal than we expect that it will be more efficient to fail @@ -1740,6 +1740,8 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, format != COGL_PIXEL_FORMAT_RGBA_8888) return FALSE; + ctx = _cogl_bitmap_get_context (bitmap); + *found_intersection = FALSE; /* NB: The most recently added journal entry is the last entry, and @@ -1759,6 +1761,7 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, float poly[16]; CoglFramebuffer *framebuffer = journal->framebuffer; uint8_t *pixel; + CoglError *ignore_error; entry_to_screen_polygon (framebuffer, entry, vertices, poly); @@ -1799,9 +1802,13 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, pixel = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + &ignore_error); if (pixel == NULL) - return FALSE; + { + cogl_error_free (ignore_error); + return FALSE; + } pixel[0] = color[0]; pixel[1] = color[1]; diff --git a/cogl/cogl-pixel-buffer.c b/cogl/cogl-pixel-buffer.c index 0c7502cc7..b664ddc2b 100644 --- a/cogl/cogl-pixel-buffer.c +++ b/cogl/cogl-pixel-buffer.c @@ -66,10 +66,11 @@ _cogl_pixel_buffer_free (CoglPixelBuffer *buffer); COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer) -CoglPixelBuffer * -cogl_pixel_buffer_new (CoglContext *context, - size_t size, - const void *data) +static CoglPixelBuffer * +_cogl_pixel_buffer_new (CoglContext *context, + size_t size, + const void *data, + CoglError **error) { CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer); CoglBuffer *buffer = COGL_BUFFER (pixel_buffer); @@ -85,14 +86,34 @@ cogl_pixel_buffer_new (CoglContext *context, _cogl_pixel_buffer_object_new (pixel_buffer); if (data) - cogl_buffer_set_data (COGL_BUFFER (pixel_buffer), - 0, - data, - size); + { + if (!_cogl_buffer_set_data (COGL_BUFFER (pixel_buffer), + 0, + data, + size, + error)) + { + cogl_object_unref (pixel_buffer); + return NULL; + } + } return pixel_buffer; } +CoglPixelBuffer * +cogl_pixel_buffer_new (CoglContext *context, + size_t size, + const void *data) +{ + CoglError *ignore_error = NULL; + CoglPixelBuffer *buffer = + _cogl_pixel_buffer_new (context, size, data, &ignore_error); + if (!buffer) + cogl_error_free (ignore_error); + return buffer; +} + static void _cogl_pixel_buffer_free (CoglPixelBuffer *buffer) { diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index b3e3a9737..ccb8b2d60 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -366,23 +366,25 @@ _cogl_sub_texture_ensure_non_quad_rendering (CoglTexture *tex) } static CoglBool -_cogl_sub_texture_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_sub_texture_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); - return cogl_texture_set_region_from_bitmap (sub_tex->full_texture, - src_x, src_y, - dst_x + sub_tex->sub_x, - dst_y + sub_tex->sub_y, - dst_width, dst_height, - bmp); + return _cogl_texture_set_region_from_bitmap (sub_tex->full_texture, + src_x, src_y, + dst_x + sub_tex->sub_x, + dst_y + sub_tex->sub_y, + dst_width, dst_height, + bmp, + error); } static CoglPixelFormat diff --git a/cogl/cogl-texture-2d-sliced-private.h b/cogl/cogl-texture-2d-sliced-private.h index 0a388ee78..760db98dc 100644 --- a/cogl/cogl-texture-2d-sliced-private.h +++ b/cogl/cogl-texture-2d-sliced-private.h @@ -53,8 +53,9 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle, CoglPixelFormat format); CoglTexture2DSliced * -_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, +_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, CoglTextureFlags flags, - CoglPixelFormat internal_format); + CoglPixelFormat internal_format, + 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 7b4fee59b..4b3c48195 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -162,7 +162,7 @@ _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds, return waste_buf; } -static void +static CoglBool _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, CoglBitmap *source_bmp, CoglTexture2D *slice_tex, @@ -174,7 +174,8 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, int src_x, int src_y, int dst_x, - int dst_y) + int dst_y, + CoglError **error) { CoglBool need_x, need_y; CoglContext *ctx = COGL_TEXTURE (tex_2ds)->context; @@ -200,10 +201,9 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, unsigned int wy, wx; CoglBitmap *waste_bmp; - bmp_data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0); - + bmp_data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (bmp_data == NULL) - return; + return FALSE; if (need_x) { @@ -234,18 +234,24 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, x_span->waste * bpp, waste_buf); - cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), - 0, /* src_x */ - 0, /* src_y */ - /* dst_x */ - x_span->size - x_span->waste, - y_iter->intersect_start - - y_span->start, /* dst_y */ - x_span->waste, /* dst_width */ - /* dst_height */ - y_iter->intersect_end - - y_iter->intersect_start, - waste_bmp); + if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), + 0, /* src_x */ + 0, /* src_y */ + /* dst_x */ + x_span->size - x_span->waste, + y_iter->intersect_start - + y_span->start, /* dst_y */ + x_span->waste, /* dst_width */ + /* dst_height */ + y_iter->intersect_end - + y_iter->intersect_start, + waste_bmp, + error)) + { + cogl_object_unref (waste_bmp); + _cogl_bitmap_unmap (source_bmp); + return FALSE; + } cogl_object_unref (waste_bmp); } @@ -288,28 +294,37 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, copy_width * bpp, waste_buf); - cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), - 0, /* src_x */ - 0, /* src_y */ - /* dst_x */ - x_iter->intersect_start - - x_iter->pos, - /* dst_y */ - y_span->size - y_span->waste, - copy_width, /* dst_width */ - y_span->waste, /* dst_height */ - waste_bmp); + if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), + 0, /* src_x */ + 0, /* src_y */ + /* dst_x */ + x_iter->intersect_start - + x_iter->pos, + /* dst_y */ + y_span->size - y_span->waste, + copy_width, /* dst_width */ + y_span->waste, /* dst_height */ + waste_bmp, + error)) + { + cogl_object_unref (waste_bmp); + _cogl_bitmap_unmap (source_bmp); + return FALSE; + } cogl_object_unref (waste_bmp); } _cogl_bitmap_unmap (source_bmp); } + + return TRUE; } static CoglBool _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, - CoglBitmap *bmp) + CoglBitmap *bmp, + CoglError **error) { CoglSpan *x_span; CoglSpan *y_span; @@ -340,16 +355,22 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, slice_num); - cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), - x_span->start, /* src x */ - y_span->start, /* src y */ - 0, /* dst x */ - 0, /* dst y */ - x_span->size - - x_span->waste, /* width */ - y_span->size - - y_span->waste, /* height */ - bmp); + if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), + x_span->start, /* src x */ + y_span->start, /* src y */ + 0, /* dst x */ + 0, /* dst y */ + x_span->size - + x_span->waste, /* width */ + y_span->size - + y_span->waste, /* height */ + bmp, + error)) + { + if (waste_buf) + g_free (waste_buf); + return FALSE; + } /* Set up a fake iterator that covers the whole slice */ x_iter.intersect_start = x_span->start; @@ -364,16 +385,22 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, y_span->waste); y_iter.pos = y_span->start; - _cogl_texture_2d_sliced_set_waste (tex_2ds, - bmp, - slice_tex, - waste_buf, - x_span, y_span, - &x_iter, &y_iter, - 0, /* src_x */ - 0, /* src_y */ - 0, /* dst_x */ - 0); /* dst_y */ + if (!_cogl_texture_2d_sliced_set_waste (tex_2ds, + bmp, + slice_tex, + waste_buf, + x_span, y_span, + &x_iter, &y_iter, + 0, /* src_x */ + 0, /* src_y */ + 0, /* dst_x */ + 0, + error)) /* dst_y */ + { + if (waste_buf) + g_free (waste_buf); + return FALSE; + } } } @@ -385,15 +412,16 @@ _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) + 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) { CoglSpan *x_span; CoglSpan *y_span; @@ -463,27 +491,40 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds, slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, slice_num); - cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), - source_x, - source_y, - local_x, /* dst x */ - local_y, /* dst y */ - inter_w, /* width */ - inter_h, /* height */ - source_bmp); + if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), + source_x, + source_y, + local_x, /* dst x */ + local_y, /* dst y */ + inter_w, /* width */ + inter_h, /* height */ + source_bmp, + error)) + { + if (waste_buf) + g_free (waste_buf); + return FALSE; + } - _cogl_texture_2d_sliced_set_waste (tex_2ds, - source_bmp, - slice_tex, - waste_buf, - x_span, y_span, - &x_iter, &y_iter, - src_x, src_y, - dst_x, dst_y); + if (!_cogl_texture_2d_sliced_set_waste (tex_2ds, + source_bmp, + slice_tex, + waste_buf, + x_span, y_span, + &x_iter, &y_iter, + src_x, src_y, + dst_x, dst_y, + error)) + { + if (waste_buf) + g_free (waste_buf); + return FALSE; + } } } - g_free (waste_buf); + if (waste_buf) + g_free (waste_buf); return TRUE; } @@ -875,9 +916,10 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx, } CoglTexture2DSliced * -_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, +_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, CoglTextureFlags flags, - CoglPixelFormat internal_format) + CoglPixelFormat internal_format, + CoglError **error) { CoglTexture2DSliced *tex_2ds; CoglBitmap *dst_bmp; @@ -908,7 +950,8 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, &internal_format, &gl_intformat, &gl_format, - &gl_type); + &gl_type, + error); if (dst_bmp == NULL) { _cogl_texture_2d_sliced_free (tex_2ds); @@ -922,7 +965,8 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, goto error; if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds, - dst_bmp)) + dst_bmp, + error)) goto error; cogl_object_unref (dst_bmp); @@ -1234,38 +1278,45 @@ _cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex) } static CoglBool -_cogl_texture_2d_sliced_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_texture_2d_sliced_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); GLenum gl_format; GLenum gl_type; + CoglBool status; bmp = _cogl_texture_prepare_for_upload (bmp, cogl_texture_get_format (tex), NULL, NULL, &gl_format, - &gl_type); + &gl_type, + error); + if (!bmp) + return FALSE; /* 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, - bmp, - gl_format, - gl_type); + 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); - return TRUE; + return status; } static CoglPixelFormat diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index 950cccef8..8517d2377 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -476,26 +476,31 @@ _cogl_texture_2d_ensure_non_quad_rendering (CoglTexture *tex) } static CoglBool -_cogl_texture_2d_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height, - CoglBitmap *bmp) +_cogl_texture_2d_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglBitmap *bmp, + CoglError **error) { CoglContext *ctx = tex->context; CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, - bmp, - dst_x, - dst_y, - src_x, - src_y, - width, - height); + if (!ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, + bmp, + dst_x, + dst_y, + src_x, + src_y, + width, + height, + error)) + { + return FALSE; + } tex_2d->mipmaps_dirty = TRUE; diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c index 0c883f972..c901c6a53 100644 --- a/cogl/cogl-texture-3d.c +++ b/cogl/cogl-texture-3d.c @@ -271,7 +271,6 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, GLenum gl_intformat; GLenum gl_format; GLenum gl_type; - uint8_t *data; CoglContext *ctx; ctx = _cogl_bitmap_get_context (bmp); @@ -293,14 +292,10 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, &internal_format, &gl_intformat, &gl_format, - &gl_type); - + &gl_type, + error); if (dst_bmp == NULL) - { - _cogl_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED, - "Bitmap conversion failed"); - return NULL; - } + return NULL; tex_3d = _cogl_texture_3d_create_base (ctx, bmp_width, height, depth, @@ -308,32 +303,53 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ - if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && - (data = _cogl_bitmap_map (dst_bmp, - COGL_BUFFER_ACCESS_READ, 0))) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { + CoglError *ignore = NULL; + uint8_t *data = _cogl_bitmap_map (dst_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; - memcpy (tex_3d->first_pixel.data, data, - _cogl_pixel_format_get_bytes_per_pixel (format)); - _cogl_bitmap_unmap (dst_bmp); + if (data) + { + memcpy (tex_3d->first_pixel.data, data, + _cogl_pixel_format_get_bytes_per_pixel (format)); + _cogl_bitmap_unmap (dst_bmp); + } + else + { + g_warning ("Failed to read first pixel of bitmap for " + "glGenerateMipmap fallback"); + cogl_error_free (ignore); + memset (tex_3d->first_pixel.data, 0, + _cogl_pixel_format_get_bytes_per_pixel (format)); + } } tex_3d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format); - ctx->texture_driver->upload_to_gl_3d (ctx, - GL_TEXTURE_3D, - tex_3d->gl_texture, - FALSE, /* is_foreign */ - height, - depth, - dst_bmp, - gl_intformat, - gl_format, - gl_type); + if (!ctx->texture_driver->upload_to_gl_3d (ctx, + GL_TEXTURE_3D, + tex_3d->gl_texture, + FALSE, /* is_foreign */ + height, + depth, + dst_bmp, + gl_intformat, + gl_format, + gl_type, + error)) + { + cogl_object_unref (dst_bmp); + cogl_object_unref (tex_3d); + return NULL; + } tex_3d->gl_format = gl_intformat; @@ -393,7 +409,8 @@ cogl_texture_3d_new_from_data (CoglContext *context, bmp_data = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); + COGL_BUFFER_MAP_HINT_DISCARD, + error); if (bmp_data == NULL) { @@ -569,17 +586,24 @@ _cogl_texture_3d_ensure_non_quad_rendering (CoglTexture *tex) } static CoglBool -_cogl_texture_3d_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_texture_3d_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { /* This function doesn't really make sense for 3D textures because it can't specify which image to upload to */ + _cogl_set_error (error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Setting a 2D region on a 3D texture isn't " + "currently supported"); + return FALSE; } diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl-texture-driver.h index 7a186ba48..780f40df8 100644 --- a/cogl/cogl-texture-driver.h +++ b/cogl/cogl-texture-driver.h @@ -63,7 +63,7 @@ struct _CoglTextureDriver * * XXX: sorry for the ridiculous number of arguments :-( */ - void + CoglBool (* upload_subregion_to_gl) (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, @@ -76,7 +76,8 @@ struct _CoglTextureDriver int height, CoglBitmap *source_bmp, GLuint source_gl_format, - GLuint source_gl_type); + GLuint source_gl_type, + CoglError **error); /* * Replaces the contents of the GL texture with the entire bitmap. On @@ -84,7 +85,7 @@ struct _CoglTextureDriver * to copy the bitmap if the rowstride is not a multiple of a possible * alignment value because there is no GL_UNPACK_ROW_LENGTH */ - void + CoglBool (* upload_to_gl) (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, @@ -92,7 +93,8 @@ struct _CoglTextureDriver CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, - GLuint source_gl_type); + GLuint source_gl_type, + CoglError **error); /* * Replaces the contents of the GL texture with the entire bitmap. The @@ -101,7 +103,7 @@ struct _CoglTextureDriver * is the number of rows between images) is inferred by dividing the * height of the bitmap by the depth. */ - void + CoglBool (* upload_to_gl_3d) (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, @@ -111,7 +113,8 @@ struct _CoglTextureDriver CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, - GLuint source_gl_type); + GLuint source_gl_type, + CoglError **error); /* * This sets up the glPixelStore state for an download to a destination with diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index a52101fbb..51fdf0bdb 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -65,14 +65,15 @@ struct _CoglTextureVtable before being passed so the implementation is expected to call _cogl_texture_prepare_for_upload with a suitable destination format before uploading */ - CoglBool (* set_region) (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bitmap); + CoglBool (* set_region) (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bitmap, + CoglError **error); /* This should copy the image data of the texture into @data. The requested format will have been first passed through @@ -233,17 +234,19 @@ _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 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 */ - + * 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, +_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, + CoglPixelFormat dst_format, CoglPixelFormat *dst_format_out, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype); + GLenum *out_glintformat, + GLenum *out_glformat, + GLenum *out_gltype, + CoglError **error); void _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); @@ -253,15 +256,6 @@ _cogl_texture_prep_gl_alignment_for_pixels_download (int bpp, int width, int rowstride); -/* Utility function to use as a fallback for getting the data of any - texture via the framebuffer */ - -CoglBool -_cogl_texture_draw_and_read (CoglTexture *texture, - CoglBitmap *target_bmp, - GLuint target_gl_format, - GLuint target_gl_type); - CoglBool _cogl_texture_is_foreign (CoglTexture *texture); @@ -301,4 +295,21 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans, CoglTextureType _cogl_texture_get_type (CoglTexture *texture); +CoglTexture * +_cogl_texture_new_from_bitmap (CoglBitmap *bitmap, + CoglTextureFlags flags, + CoglPixelFormat internal_format, + CoglError **error); + +CoglBool +_cogl_texture_set_region_from_bitmap (CoglTexture *texture, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + CoglBitmap *bmp, + CoglError **error); + #endif /* __COGL_TEXTURE_PRIVATE_H */ diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c index 1ffeb839d..e8bb965f2 100644 --- a/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl-texture-rectangle.c @@ -38,6 +38,7 @@ #include "cogl-journal-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" +#include "cogl-util-gl-private.h" #include #include @@ -185,7 +186,7 @@ _cogl_texture_rectangle_create_base (CoglContext *ctx, tex_rect->format = internal_format; - return tex_rect; + return _cogl_texture_rectangle_object_new (tex_rect); } CoglTextureRectangle * @@ -196,9 +197,10 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx, CoglError **error) { CoglTextureRectangle *tex_rect; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; + GLenum gl_error; /* Since no data, we need some internal format */ if (internal_format == COGL_PIXEL_FORMAT_ANY) @@ -226,10 +228,21 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx, _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, tex_rect->is_foreign); - GE( ctx, glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat, - width, height, 0, gl_format, gl_type, NULL) ); - return _cogl_texture_rectangle_object_new (tex_rect); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat, + width, height, 0, gl_format, gl_type, NULL); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + { + cogl_object_unref (tex_rect); + return NULL; + } + + return tex_rect; } CoglTextureRectangle * @@ -264,7 +277,8 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp, &internal_format, &gl_intformat, &gl_format, - &gl_type); + &gl_type, + error); if (dst_bmp == NULL) return NULL; @@ -278,20 +292,26 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp, ctx->texture_driver->gen (ctx, GL_TEXTURE_RECTANGLE_ARB, internal_format); - ctx->texture_driver->upload_to_gl (ctx, - GL_TEXTURE_RECTANGLE_ARB, - tex_rect->gl_texture, - FALSE, - dst_bmp, - gl_intformat, - gl_format, - gl_type); + if (!ctx->texture_driver->upload_to_gl (ctx, + GL_TEXTURE_RECTANGLE_ARB, + tex_rect->gl_texture, + FALSE, + dst_bmp, + gl_intformat, + gl_format, + gl_type, + error)) + { + cogl_object_unref (dst_bmp); + cogl_object_unref (tex_rect); + return NULL; + } tex_rect->gl_format = gl_intformat; cogl_object_unref (dst_bmp); - return _cogl_texture_rectangle_object_new (tex_rect); + return tex_rect; } CoglTextureRectangle * @@ -416,7 +436,7 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx, tex_rect->gl_legacy_texobj_min_filter = GL_FALSE; tex_rect->gl_legacy_texobj_mag_filter = GL_FALSE; - return _cogl_texture_rectangle_object_new (tex_rect); + return tex_rect; } static int @@ -527,42 +547,49 @@ _cogl_texture_rectangle_ensure_non_quad_rendering (CoglTexture *tex) } static CoglBool -_cogl_texture_rectangle_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_texture_rectangle_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); 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); + &gl_type, + error); + if (!bmp) + return FALSE; /* Send data to GL */ - ctx->texture_driver->upload_subregion_to_gl (ctx, - GL_TEXTURE_RECTANGLE_ARB, - tex_rect->gl_texture, - FALSE, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - bmp, - gl_format, - gl_type); + status = + ctx->texture_driver->upload_subregion_to_gl (ctx, + GL_TEXTURE_RECTANGLE_ARB, + tex_rect->gl_texture, + FALSE, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + bmp, + gl_format, + gl_type, + error); cogl_object_unref (bmp); - return TRUE; + return status; } static CoglBool diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index d226a9d01..9e5252411 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -55,6 +55,7 @@ #include "cogl1-context.h" #include "cogl-sub-texture.h" #include "cogl-primitive-texture.h" +#include "cogl-error-private.h" #include #include @@ -183,18 +184,18 @@ _cogl_texture_determine_internal_format (CoglPixelFormat src_format, } CoglBitmap * -_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, - CoglPixelFormat dst_format, +_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, + CoglPixelFormat dst_format, CoglPixelFormat *dst_format_out, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype) + 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; - _COGL_GET_CONTEXT (ctx, NULL); - dst_format = _cogl_texture_determine_internal_format (src_format, dst_format); @@ -222,7 +223,8 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, dst_format)) { dst_bmp = _cogl_bitmap_convert (src_bmp, - src_format ^ COGL_PREMULT_BIT); + src_format ^ COGL_PREMULT_BIT, + error); if (dst_bmp == NULL) return NULL; @@ -256,7 +258,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, out_gltype); if (closest_format != src_format) - dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format); + dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format, error); else dst_bmp = cogl_object_ref (src_bmp); } @@ -354,25 +356,22 @@ cogl_texture_new_with_size (unsigned int width, return tex; } -CoglTexture * -cogl_texture_new_from_data (unsigned int width, - unsigned int height, - CoglTextureFlags flags, - CoglPixelFormat format, - CoglPixelFormat internal_format, - unsigned int rowstride, - const uint8_t *data) +static CoglTexture * +_cogl_texture_new_from_data (CoglContext *ctx, + int width, + int height, + CoglTextureFlags flags, + CoglPixelFormat format, + CoglPixelFormat internal_format, + int rowstride, + const uint8_t *data, + CoglError **error) { CoglBitmap *bmp; CoglTexture *tex; - _COGL_GET_CONTEXT (ctx, NULL); - - if (format == COGL_PIXEL_FORMAT_ANY) - return NULL; - - if (data == NULL) - return NULL; + _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); + _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) @@ -385,7 +384,7 @@ cogl_texture_new_from_data (unsigned int width, rowstride, (uint8_t *) data); - tex = cogl_texture_new_from_bitmap (bmp, flags, internal_format); + tex = _cogl_texture_new_from_bitmap (bmp, flags, internal_format, error); cogl_object_unref (bmp); @@ -393,21 +392,60 @@ cogl_texture_new_from_data (unsigned int width, } CoglTexture * -cogl_texture_new_from_bitmap (CoglBitmap *bitmap, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_from_data (int width, + int height, + CoglTextureFlags flags, + CoglPixelFormat format, + CoglPixelFormat internal_format, + int rowstride, + const uint8_t *data) { - CoglAtlasTexture *atlas_tex; + CoglError *ignore_error = NULL; CoglTexture *tex; - _COGL_GET_CONTEXT (ctx, FALSE); + _COGL_GET_CONTEXT (ctx, NULL); + + tex = _cogl_texture_new_from_data (ctx, + width, height, + flags, + format, internal_format, + rowstride, + data, + &ignore_error); + if (!tex) + cogl_error_free (ignore_error); + return tex; +} + +CoglTexture * +_cogl_texture_new_from_bitmap (CoglBitmap *bitmap, + CoglTextureFlags flags, + CoglPixelFormat internal_format, + CoglError **error) +{ + CoglContext *ctx = _cogl_bitmap_get_context (bitmap); + CoglAtlasTexture *atlas_tex; + CoglTexture *tex; + CoglError *internal_error = NULL; /* First try putting the texture in the atlas */ if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap, flags, - internal_format))) + internal_format, + &internal_error))) return COGL_TEXTURE (atlas_tex); + if (cogl_error_matches (internal_error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_NO_MEMORY)) + { + _cogl_propogate_error (error, internal_error); + return NULL; + } + + cogl_error_free (internal_error); + internal_error = NULL; + /* If that doesn't work try a fast path 2D texture */ if ((_cogl_util_is_pot (bitmap->width) && _cogl_util_is_pot (bitmap->height)) || @@ -416,7 +454,21 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap, { tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap, internal_format, - NULL)); + &internal_error)); + + if (cogl_error_matches (internal_error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_NO_MEMORY)) + { + _cogl_propogate_error (error, internal_error); + return NULL; + } + + if (!tex) + { + cogl_error_free (internal_error); + internal_error = NULL; + } } else tex = NULL; @@ -432,12 +484,27 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap, /* Otherwise create a sliced texture */ tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap, flags, - internal_format)); + internal_format, + error)); } return tex; } +CoglTexture * +cogl_texture_new_from_bitmap (CoglBitmap *bitmap, + CoglTextureFlags flags, + CoglPixelFormat internal_format) +{ + CoglError *ignore_error = NULL; + CoglTexture *tex = + _cogl_texture_new_from_bitmap (bitmap, flags, internal_format, + &ignore_error); + if (!tex) + cogl_error_free (ignore_error); + return tex; +} + CoglTexture * cogl_texture_new_from_file (const char *filename, CoglTextureFlags flags, @@ -465,8 +532,13 @@ cogl_texture_new_from_file (const char *filename, 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)) - texture = cogl_texture_new_from_bitmap (bmp, flags, 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); + } cogl_object_unref (bmp); @@ -664,14 +736,15 @@ _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture) } CoglBool -cogl_texture_set_region_from_bitmap (CoglTexture *texture, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_texture_set_region_from_bitmap (CoglTexture *texture, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + CoglBitmap *bmp, + CoglError **error) { CoglBool ret; @@ -695,24 +768,50 @@ cogl_texture_set_region_from_bitmap (CoglTexture *texture, src_x, src_y, dst_x, dst_y, dst_width, dst_height, - bmp); + bmp, + error); return ret; } CoglBool -cogl_texture_set_region (CoglTexture *texture, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - int width, - int height, - CoglPixelFormat format, - unsigned int rowstride, - const uint8_t *data) +cogl_texture_set_region_from_bitmap (CoglTexture *texture, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + CoglBitmap *bitmap) +{ + CoglError *ignore_error = NULL; + CoglBool status = + _cogl_texture_set_region_from_bitmap (texture, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + bitmap, + &ignore_error); + + if (!status) + cogl_error_free (ignore_error); + return status; +} + +static CoglBool +_cogl_texture_set_region (CoglTexture *texture, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + int width, + int height, + CoglPixelFormat format, + unsigned int rowstride, + const uint8_t *data, + CoglError **error) { CoglContext *ctx = texture->context; CoglBitmap *source_bmp; @@ -736,17 +835,47 @@ cogl_texture_set_region (CoglTexture *texture, rowstride, (uint8_t *) data); - ret = cogl_texture_set_region_from_bitmap (texture, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - source_bmp); + ret = _cogl_texture_set_region_from_bitmap (texture, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + source_bmp, + error); cogl_object_unref (source_bmp); return ret; } +CoglBool +cogl_texture_set_region (CoglTexture *texture, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + int width, + int height, + CoglPixelFormat format, + unsigned int rowstride, + const uint8_t *data) +{ + CoglError *ignore_error = NULL; + CoglBool status = _cogl_texture_set_region (texture, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + width, height, + format, + rowstride, + data, + &ignore_error); + if (!status) + cogl_error_free (ignore_error); + return status; +} + /* Reads back the contents of a texture by rendering it to the framebuffer * and reading back the resulting pixels. * @@ -760,12 +889,13 @@ cogl_texture_set_region (CoglTexture *texture, * NB: Normally this approach isn't normally used since we can just use * glGetTexImage, but may be used as a fallback in some circumstances. */ -static void +static CoglBool do_texture_draw_and_read (CoglFramebuffer *fb, CoglPipeline *pipeline, CoglTexture *texture, CoglBitmap *target_bmp, - float *viewport) + float *viewport, + CoglError **error) { float rx1, ry1; float rx2, ry2; @@ -828,24 +958,36 @@ do_texture_draw_and_read (CoglFramebuffer *fb, width, height, COGL_PIXEL_FORMAT_RGBA_8888_PRE); - cogl_framebuffer_read_pixels_into_bitmap - (fb, - viewport[0], viewport[1], - COGL_READ_PIXELS_COLOR_BUFFER, - rect_bmp); + if (!_cogl_framebuffer_read_pixels_into_bitmap + (fb, + viewport[0], viewport[1], + COGL_READ_PIXELS_COLOR_BUFFER, + rect_bmp, + error)) + { + cogl_object_unref (rect_bmp); + return FALSE; + } /* Copy to target bitmap */ - _cogl_bitmap_copy_subregion (rect_bmp, - target_bmp, - 0,0, - rx1,ry1, - width, - height); + if (!_cogl_bitmap_copy_subregion (rect_bmp, + target_bmp, + 0, 0, + rx1, ry1, + width, + height, + error)) + { + cogl_object_unref (rect_bmp); + return FALSE; + } /* Free temp bitmap */ cogl_object_unref (rect_bmp); } } + + return TRUE; } /* Reads back the contents of a texture by rendering it to the framebuffer @@ -854,38 +996,30 @@ do_texture_draw_and_read (CoglFramebuffer *fb, * NB: Normally this approach isn't normally used since we can just use * glGetTexImage, but may be used as a fallback in some circumstances. */ -CoglBool +static CoglBool _cogl_texture_draw_and_read (CoglTexture *texture, CoglBitmap *target_bmp, GLuint target_gl_format, - GLuint target_gl_type) + GLuint target_gl_type, + CoglError **error) { - int bpp; CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer (); - float viewport[4]; - CoglBitmap *alpha_bmp; - int target_width = cogl_bitmap_get_width (target_bmp); - int target_height = cogl_bitmap_get_height (target_bmp); - int target_rowstride = cogl_bitmap_get_rowstride (target_bmp); CoglContext *ctx = framebuffer->context; + float save_viewport[4]; + float viewport[4]; + CoglBool status = FALSE; - bpp = _cogl_pixel_format_get_bytes_per_pixel (COGL_PIXEL_FORMAT_RGBA_8888); - - /* Viewport needs to have some size and be inside the window for this */ - cogl_framebuffer_get_viewport4fv (framebuffer, viewport); - if (viewport[0] < 0 || viewport[1] < 0 || - viewport[2] <= 0 || viewport[3] <= 0) - return FALSE; - - /* Setup orthographic projection into current viewport (0,0 in top-left - * corner to draw the texture upside-down so we match the way cogl_read_pixels - * works) - */ + viewport[0] = 0; + viewport[1] = 0; + viewport[2] = cogl_framebuffer_get_width (framebuffer); + viewport[3] = cogl_framebuffer_get_height (framebuffer); + cogl_framebuffer_get_viewport4fv (framebuffer, save_viewport); _cogl_framebuffer_push_projection (framebuffer); cogl_framebuffer_orthographic (framebuffer, 0, 0, - viewport[2], viewport[3], + viewport[2], + viewport[3], 0, 100); cogl_framebuffer_push_matrix (framebuffer); @@ -912,36 +1046,38 @@ _cogl_texture_draw_and_read (CoglTexture *texture, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); - do_texture_draw_and_read (framebuffer, - ctx->texture_download_pipeline, - texture, target_bmp, viewport); + if (!do_texture_draw_and_read (framebuffer, + ctx->texture_download_pipeline, + texture, target_bmp, viewport, + error)) + return FALSE; - /* Check whether texture has alpha and framebuffer not */ - /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer - still doesn't seem to have an alpha buffer. This might be just - a PowerVR issue. - GLint r_bits, g_bits, b_bits, a_bits; - GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); - GE( ctx, glGetIntegerv (GL_RED_BITS, &r_bits) ); - GE( ctx, glGetIntegerv (GL_GREEN_BITS, &g_bits) ); - GE( ctx, glGetIntegerv (GL_BLUE_BITS, &b_bits) ); - printf ("R bits: %d\n", r_bits); - printf ("G bits: %d\n", g_bits); - printf ("B bits: %d\n", b_bits); - printf ("A bits: %d\n", a_bits); */ + /* XXX: As an alleged PowerVR driver bug workaround where the driver + * is apparently not maintaining the alpha component of some + * framebuffers we render the alpha component of the texture + * separately to be sure we retrieve all components of the texture. + * + * TODO: verify if this is still an issue + */ if ((cogl_texture_get_format (texture) & COGL_A_BIT)/* && a_bits == 0*/) { uint8_t *srcdata; uint8_t *dstdata; uint8_t *srcpixel; uint8_t *dstpixel; - int x,y; + int target_width = cogl_bitmap_get_width (target_bmp); + int target_height = cogl_bitmap_get_height (target_bmp); + int target_rowstride = cogl_bitmap_get_rowstride (target_bmp); + int bpp = _cogl_pixel_format_get_bytes_per_pixel (COGL_PIXEL_FORMAT_RGBA_8888); int alpha_rowstride = bpp * target_width; + CoglBitmap *alpha_bmp; + int x,y; if ((dstdata = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD)) == NULL) - return FALSE; + COGL_BUFFER_MAP_HINT_DISCARD, + error)) == NULL) + goto EXIT; /* Create temp bitmap for alpha values */ alpha_bmp = @@ -956,15 +1092,24 @@ _cogl_texture_draw_and_read (CoglTexture *texture, "RGBA = REPLACE (TEXTURE[A])", NULL); - do_texture_draw_and_read (framebuffer, - ctx->texture_download_pipeline, - texture, alpha_bmp, viewport); + if (!do_texture_draw_and_read (framebuffer, + ctx->texture_download_pipeline, + texture, alpha_bmp, viewport, + error)) + { + cogl_object_unref (alpha_bmp); + _cogl_bitmap_unmap (target_bmp); + goto EXIT; + } /* Copy temp R to target A */ + /* Note: we don't try to catch errors since "mapping" an + * malloc buffer should never fail */ srcdata = _cogl_bitmap_map (alpha_bmp, COGL_BUFFER_ACCESS_READ, - 0 /* hints */); + 0 /* hints */, + NULL); for (y=0; ymessage); + cogl_error_free (ignore_error); + cogl_object_unref (target_bmp); + return 0; + } + } /* Was intermediate used? */ if (closest_format != format) { CoglBitmap *new_bmp; CoglBool result; + CoglError *error = NULL; /* Convert to requested format directly into the user's buffer */ new_bmp = cogl_bitmap_new_for_data (ctx, @@ -1303,11 +1482,14 @@ cogl_texture_get_data (CoglTexture *texture, format, rowstride, data); - result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp); + result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp, &error); if (!result) - /* Return failure after cleaning up */ - byte_size = 0; + { + cogl_error_free (error); + /* Return failure after cleaning up */ + byte_size = 0; + } cogl_object_unref (new_bmp); } diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index c1462eddf..6714b65c4 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -173,13 +173,13 @@ cogl_texture_new_from_file (const char *filename, * Since: 0.8 */ CoglTexture * -cogl_texture_new_from_data (unsigned int width, - unsigned int height, - CoglTextureFlags flags, - CoglPixelFormat format, - CoglPixelFormat internal_format, - unsigned int rowstride, - const uint8_t *data); +cogl_texture_new_from_data (int width, + int height, + CoglTextureFlags flags, + CoglPixelFormat format, + CoglPixelFormat internal_format, + int rowstride, + const uint8_t *data); /** * cogl_texture_new_from_foreign: diff --git a/cogl/cogl.symbols b/cogl/cogl.symbols index 97fa523df..5db670257 100644 --- a/cogl/cogl.symbols +++ b/cogl/cogl.symbols @@ -912,7 +912,6 @@ _cogl_system_error_domain _cogl_texture_associate_framebuffer _cogl_texture_can_hardware_repeat _cogl_texture_determine_internal_format -_cogl_texture_draw_and_read _cogl_texture_ensure_non_quad_rendering _cogl_texture_flush_journal_rendering _cogl_texture_free diff --git a/cogl/cogl2-path.c b/cogl/cogl2-path.c index e4dad30ea..122447fbf 100644 --- a/cogl/cogl2-path.c +++ b/cogl/cogl2-path.c @@ -1426,9 +1426,9 @@ _cogl_path_build_stroke_attribute_buffer (CoglPath *path) return; data->stroke_attribute_buffer = - cogl_attribute_buffer_new (data->context, - data->path_nodes->len * sizeof (floatVec2), - NULL); + cogl_attribute_buffer_new_with_size (data->context, + data->path_nodes->len * + sizeof (floatVec2)); buffer = COGL_BUFFER (data->stroke_attribute_buffer); buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer); diff --git a/cogl/driver/gl/cogl-attribute-gl.c b/cogl/driver/gl/cogl-attribute-gl.c index 9210b954c..2fa1ec2ad 100644 --- a/cogl/driver/gl/cogl-attribute-gl.c +++ b/cogl/driver/gl/cogl-attribute-gl.c @@ -467,8 +467,16 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, { attribute_buffer = cogl_attribute_get_buffer (attribute); buffer = COGL_BUFFER (attribute_buffer); - base = _cogl_buffer_gl_bind (buffer, - COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER); + + /* Note: we don't try and catch errors with binding buffers + * here since OOM errors at this point indicate that nothing + * has yet been uploaded to attribute buffer which we + * consider to be a programmer error. + */ + base = + _cogl_buffer_gl_bind (buffer, + COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, + NULL); if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL) setup_generic_buffered_attribute (ctx, pipeline, attribute, base); diff --git a/cogl/driver/gl/cogl-buffer-gl-private.h b/cogl/driver/gl/cogl-buffer-gl-private.h index 583e0c119..975927fb6 100644 --- a/cogl/driver/gl/cogl-buffer-gl-private.h +++ b/cogl/driver/gl/cogl-buffer-gl-private.h @@ -44,7 +44,8 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints); + CoglBufferMapHint hints, + CoglError **error); void _cogl_buffer_gl_unmap (CoglBuffer *buffer); @@ -53,10 +54,13 @@ CoglBool _cogl_buffer_gl_set_data (CoglBuffer *buffer, unsigned int offset, const void *data, - unsigned int size); + unsigned int size, + CoglError **error); void * -_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target); +_cogl_buffer_gl_bind (CoglBuffer *buffer, + CoglBufferBindTarget target, + CoglError **error); void _cogl_buffer_gl_unbind (CoglBuffer *buffer); diff --git a/cogl/driver/gl/cogl-buffer-gl.c b/cogl/driver/gl/cogl-buffer-gl.c index 673dbf1ad..e9554375a 100644 --- a/cogl/driver/gl/cogl-buffer-gl.c +++ b/cogl/driver/gl/cogl-buffer-gl.c @@ -31,6 +31,8 @@ #include "cogl-context-private.h" #include "cogl-buffer-gl-private.h" +#include "cogl-error-private.h" +#include "cogl-util-gl-private.h" /* * GL/GLES compatibility defines for the buffer API: @@ -126,22 +128,34 @@ convert_bind_target_to_gl_target (CoglBufferBindTarget target) } } -static void -recreate_store (CoglBuffer *buffer) +static CoglBool +recreate_store (CoglBuffer *buffer, + CoglError **error) { + CoglContext *ctx = buffer->context; GLenum gl_target; GLenum gl_enum; + GLenum gl_error; /* This assumes the buffer is already bound */ gl_target = convert_bind_target_to_gl_target (buffer->last_target); gl_enum = update_hints_to_gl_enum (buffer); - GE( buffer->context, glBufferData (gl_target, - buffer->size, - NULL, - gl_enum) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glBufferData (gl_target, + buffer->size, + NULL, + gl_enum); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + return FALSE; + buffer->store_created = TRUE; + return TRUE; } GLenum @@ -188,19 +202,26 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, - CoglBufferMapHint hints) + CoglBufferMapHint hints, + CoglError **error) { uint8_t *data; CoglBufferBindTarget target; GLenum gl_target; CoglContext *ctx = buffer->context; + GLenum gl_error; - if ((access & COGL_BUFFER_ACCESS_READ) && - !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) - return NULL; - if ((access & COGL_BUFFER_ACCESS_WRITE) && - !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE)) - return NULL; + if (((access & COGL_BUFFER_ACCESS_READ) && + !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) || + ((access & COGL_BUFFER_ACCESS_WRITE) && + !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))) + { + _cogl_set_error (error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Tried to map a buffer with unsupported access mode"); + return NULL; + } target = buffer->last_target; _cogl_buffer_bind_no_create (buffer, target); @@ -226,14 +247,30 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, gl_access |= GL_MAP_INVALIDATE_RANGE_BIT; if (!buffer->store_created) - recreate_store (buffer); + { + if (!recreate_store (buffer, error)) + { + _cogl_buffer_gl_unbind (buffer); + return NULL; + } + } - GE_RET( data, - ctx, - glMapBufferRange (gl_target, - offset, - size, - gl_access) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + data = ctx->glMapBufferRange (gl_target, + offset, + size, + gl_access); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + { + _cogl_buffer_gl_unbind (buffer); + return NULL; + } + + _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); } else { @@ -244,15 +281,30 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, (hints & COGL_BUFFER_MAP_HINT_DISCARD) || ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && offset == 0 && size >= buffer->size)) - recreate_store (buffer); + { + if (!recreate_store (buffer, error)) + { + _cogl_buffer_gl_unbind (buffer); + return NULL; + } + } - GE_RET( data, - ctx, - glMapBuffer (gl_target, - _cogl_buffer_access_to_gl_enum (access)) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; - if (data) - data += offset; + data = ctx->glMapBuffer (gl_target, + _cogl_buffer_access_to_gl_enum (access)); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + { + _cogl_buffer_gl_unbind (buffer); + return NULL; + } + + _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); + + data += offset; } if (data) @@ -281,26 +333,50 @@ CoglBool _cogl_buffer_gl_set_data (CoglBuffer *buffer, unsigned int offset, const void *data, - unsigned int size) + unsigned int size, + CoglError **error) { CoglBufferBindTarget target; GLenum gl_target; CoglContext *ctx = buffer->context; + GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; target = buffer->last_target; - _cogl_buffer_gl_bind (buffer, target); + + _cogl_buffer_gl_bind (buffer, target, &internal_error); + + /* NB: _cogl_buffer_gl_bind() may return NULL in non-error + * conditions so we have to explicity check internal_error + * to see if an exception was thrown. + */ + if (internal_error) + { + _cogl_propogate_error (error, internal_error); + return FALSE; + } gl_target = convert_bind_target_to_gl_target (target); - GE( ctx, glBufferSubData (gl_target, offset, size, data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glBufferSubData (gl_target, offset, size, data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_buffer_gl_unbind (buffer); - return TRUE; + return status; } void * -_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target) +_cogl_buffer_gl_bind (CoglBuffer *buffer, + CoglBufferBindTarget target, + CoglError **error) { void *ret; @@ -311,7 +387,13 @@ _cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target) * store is created. */ if ((buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) && !buffer->store_created) - recreate_store (buffer); + { + if (!recreate_store (buffer, error)) + { + _cogl_buffer_gl_unbind (buffer); + return NULL; + } + } return ret; } diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c index 4a6f62af6..43874f69f 100644 --- a/cogl/driver/gl/cogl-framebuffer-gl.c +++ b/cogl/driver/gl/cogl-framebuffer-gl.c @@ -1067,7 +1067,14 @@ _cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer, attributes, n_attributes); buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); - base = _cogl_buffer_gl_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER); + + /* Note: we don't try and catch errors with binding the index buffer + * here since OOM errors at this point indicate that nothing has yet + * been uploaded to the indices buffer which we consider to be a + * programmer error. + */ + base = _cogl_buffer_gl_bind (buffer, + COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, NULL); buffer_offset = cogl_indices_get_offset (indices); index_size = sizeof_index_type (cogl_indices_get_type (indices)); diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h index 52378ffac..ac0c89f07 100644 --- a/cogl/driver/gl/cogl-texture-2d-gl-private.h +++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h @@ -93,7 +93,7 @@ _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d); void _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); -void +CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, CoglBitmap *bitmap, int dst_x, @@ -101,7 +101,8 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, - int height); + int height, + CoglError **error); void _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c index 224436f44..6087f30f3 100644 --- a/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/driver/gl/cogl-texture-2d-gl.c @@ -143,20 +143,16 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, GLenum gl_intformat; GLenum gl_format; GLenum gl_type; - uint8_t *data; - if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp, - internal_format, - &internal_format, - &gl_intformat, - &gl_format, - &gl_type)) == NULL) - { - _cogl_set_error (error, COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_FORMAT, - "Failed to prepare texture upload due to format"); - return NULL; - } + dst_bmp = _cogl_texture_prepare_for_upload (bmp, + internal_format, + &internal_format, + &gl_intformat, + &gl_format, + &gl_type, + error); + if (!dst_bmp) + return NULL; tex_2d = _cogl_texture_2d_create_base (ctx, cogl_bitmap_get_width (bmp), @@ -165,29 +161,49 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ - if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && - (data = _cogl_bitmap_map (dst_bmp, - COGL_BUFFER_ACCESS_READ, 0))) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { + CoglError *ignore = NULL; + uint8_t *data = _cogl_bitmap_map (dst_bmp, + COGL_BUFFER_ACCESS_READ, 0, + &ignore); CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp); + tex_2d->first_pixel.gl_format = gl_format; tex_2d->first_pixel.gl_type = gl_type; - memcpy (tex_2d->first_pixel.data, data, - _cogl_pixel_format_get_bytes_per_pixel (format)); - _cogl_bitmap_unmap (dst_bmp); + if (data) + { + memcpy (tex_2d->first_pixel.data, data, + _cogl_pixel_format_get_bytes_per_pixel (format)); + _cogl_bitmap_unmap (dst_bmp); + } + else + { + g_warning ("Failed to read first pixel of bitmap for " + "glGenerateMipmap fallback"); + cogl_error_free (ignore); + memset (tex_2d->first_pixel.data, 0, + _cogl_pixel_format_get_bytes_per_pixel (format)); + } } tex_2d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); - ctx->texture_driver->upload_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, - FALSE, - dst_bmp, - gl_intformat, - gl_format, - gl_type); + if (!ctx->texture_driver->upload_to_gl (ctx, + GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE, + dst_bmp, + gl_intformat, + gl_format, + gl_type, + error)) + { + cogl_object_unref (dst_bmp); + cogl_object_unref (tex_2d); + return NULL; + } tex_2d->gl_format = gl_intformat; @@ -502,7 +518,7 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) #endif } -void +CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, CoglBitmap *bmp, int dst_x, @@ -510,50 +526,70 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, - int height) + int height, + CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; GLenum gl_format; GLenum gl_type; - uint8_t *data; + CoglBool status = TRUE; bmp = _cogl_texture_prepare_for_upload (bmp, cogl_texture_get_format (tex), NULL, NULL, &gl_format, - &gl_type); + &gl_type, + error); + if (!bmp) + return FALSE; /* 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) && - (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 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); CoglPixelFormat bpp = _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp)); + tex_2d->first_pixel.gl_format = gl_format; tex_2d->first_pixel.gl_type = gl_type; - memcpy (tex_2d->first_pixel.data, - data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x, - bpp); - _cogl_bitmap_unmap (bmp); + if (data) + { + memcpy (tex_2d->first_pixel.data, + data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x, + bpp); + _cogl_bitmap_unmap (bmp); + } + else + { + g_warning ("Failed to read first bitmap pixel for " + "glGenerateMipmap fallback"); + cogl_error_free (ignore); + memset (tex_2d->first_pixel.data, 0, bpp); + } } /* Send data to GL */ - ctx->texture_driver->upload_subregion_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, - FALSE, - src_x, src_y, - dst_x, dst_y, - width, height, - bmp, - gl_format, - gl_type); + status = ctx->texture_driver->upload_subregion_to_gl (ctx, + GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE, + src_x, src_y, + dst_x, dst_y, + width, height, + bmp, + gl_format, + gl_type, + error); cogl_object_unref (bmp); + + return status; } void diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/driver/gl/gl/cogl-texture-driver-gl.c index 88f58fa03..76900cafe 100644 --- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c +++ b/cogl/driver/gl/gl/cogl-texture-driver-gl.c @@ -40,6 +40,8 @@ #include "cogl-object-private.h" #include "cogl-primitives.h" #include "cogl-pipeline-opengl-private.h" +#include "cogl-util-gl-private.h" +#include "cogl-error-private.h" #include #include @@ -164,26 +166,39 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, pixels_bpp); } -static void +static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height, + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + 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) + GLuint source_gl_format, + GLuint source_gl_type, + CoglError **error) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); + GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; - data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); + + /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we + * have to explicitly check the cogl error pointer to catch + * problems... */ + if (internal_error) + { + _cogl_propogate_error (error, internal_error); + return FALSE; + } /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, @@ -195,31 +210,45 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); - GE( ctx, glTexSubImage2D (gl_target, 0, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexSubImage2D (gl_target, 0, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); + + return status; } -static void +static CoglBool _cogl_texture_driver_upload_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type) + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + CoglBitmap *source_bmp, + GLint internal_gl_format, + GLuint source_gl_format, + GLuint source_gl_type, + CoglError **error) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); + GLenum gl_error; + CoglBool status = TRUE; - data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); + if (!data) + return FALSE; /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, @@ -228,35 +257,49 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); - GE( ctx, glTexImage2D (gl_target, 0, - internal_gl_format, - cogl_bitmap_get_width (source_bmp), - cogl_bitmap_get_height (source_bmp), - 0, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage2D (gl_target, 0, + internal_gl_format, + cogl_bitmap_get_width (source_bmp), + cogl_bitmap_get_height (source_bmp), + 0, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); + + return status; } -static void +static CoglBool _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - GLint height, - GLint depth, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type) + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + GLint height, + GLint depth, + CoglBitmap *source_bmp, + GLint internal_gl_format, + GLuint source_gl_format, + GLuint source_gl_type, + CoglError **error) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); + GLenum gl_error; + CoglBool status = TRUE; - data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); + if (!data) + return FALSE; /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, @@ -267,18 +310,27 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); - GE( ctx, glTexImage3D (gl_target, - 0, /* level */ - internal_gl_format, - cogl_bitmap_get_width (source_bmp), - height, - depth, - 0, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage3D (gl_target, + 0, /* level */ + internal_gl_format, + cogl_bitmap_get_width (source_bmp), + height, + depth, + 0, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); + + return status; } static CoglBool diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/driver/gl/gles/cogl-texture-driver-gles.c index b42d0fb09..945bc2bec 100644 --- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c +++ b/cogl/driver/gl/gles/cogl-texture-driver-gles.c @@ -40,6 +40,8 @@ #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-primitives.h" +#include "cogl-util-gl-private.h" +#include "cogl-error-private.h" #include #include @@ -140,7 +142,8 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, static CoglBitmap * prepare_bitmap_alignment_for_upload (CoglContext *ctx, - CoglBitmap *src_bmp) + CoglBitmap *src_bmp, + CoglError **error) { CoglPixelFormat format = cogl_bitmap_get_format (src_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); @@ -163,29 +166,33 @@ prepare_bitmap_alignment_for_upload (CoglContext *ctx, /* Otherwise we need to copy the bitmap to pack the alignment because GLES has no GL_ROW_LENGTH */ else - return _cogl_bitmap_copy (src_bmp); + return _cogl_bitmap_copy (src_bmp, error); } -static void +static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - 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) + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + 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) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); CoglBitmap *slice_bmp; int rowstride; + GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; /* If we have the GL_EXT_unpack_subimage extension then we can upload from subregions directly. Otherwise we may need to copy @@ -199,47 +206,76 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, _cogl_bitmap_new_with_malloc_buffer (ctx, width, height, source_format); - _cogl_bitmap_copy_subregion (source_bmp, - slice_bmp, - src_x, src_y, - 0, 0, /* dst_x/y */ - width, height); + if (!_cogl_bitmap_copy_subregion (source_bmp, + slice_bmp, + src_x, src_y, + 0, 0, /* dst_x/y */ + width, height, + error)) + { + cogl_object_unref (slice_bmp); + return FALSE; + } src_x = src_y = 0; } else - slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp); + { + slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); + if (!slice_bmp) + return FALSE; + } rowstride = cogl_bitmap_get_rowstride (slice_bmp); /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp); - data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); + + /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we + * have to explicitly check the cogl error pointer to catch + * problems... */ + if (internal_error) + { + _cogl_propogate_error (error, internal_error); + cogl_object_unref (slice_bmp); + return FALSE; + } _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); - GE( ctx, glTexSubImage2D (gl_target, 0, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexSubImage2D (gl_target, 0, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_bitmap_gl_unbind (slice_bmp); cogl_object_unref (slice_bmp); + + return status; } -static void +static CoglBool _cogl_texture_driver_upload_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type) + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + CoglBitmap *source_bmp, + GLint internal_gl_format, + GLuint source_gl_format, + GLuint source_gl_type, + CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); @@ -248,8 +284,13 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, int bmp_height = cogl_bitmap_get_height (source_bmp); CoglBitmap *bmp; uint8_t *data; + GLenum gl_error; + CoglBool status = TRUE; + + bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); + if (!bmp) + return FALSE; - bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp); rowstride = cogl_bitmap_get_rowstride (bmp); /* Setup gl alignment to match rowstride and top-left corner */ @@ -257,32 +298,47 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); - data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0, error); + if (!data) + { + cogl_object_unref (bmp); + return FALSE; + } - GE( ctx, glTexImage2D (gl_target, 0, - internal_gl_format, - bmp_width, bmp_height, - 0, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage2D (gl_target, 0, + internal_gl_format, + bmp_width, bmp_height, + 0, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + status = FALSE; _cogl_bitmap_gl_unbind (bmp); cogl_object_unref (bmp); + + return status; } -static void +static CoglBool _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBool is_foreign, - GLint height, - GLint depth, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type) + GLenum gl_target, + GLuint gl_handle, + CoglBool is_foreign, + GLint height, + GLint depth, + CoglBitmap *source_bmp, + GLint internal_gl_format, + GLuint source_gl_format, + GLuint source_gl_type, + CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); @@ -290,6 +346,7 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, int bmp_width = cogl_bitmap_get_width (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp); uint8_t *data; + GLenum gl_error; _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); @@ -309,16 +366,23 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, /* Initialize the texture with empty data and then upload each image with a sub-region update */ - GE( ctx, glTexImage3D (gl_target, - 0, /* level */ - internal_gl_format, - bmp_width, - height, - depth, - 0, - source_gl_format, - source_gl_type, - NULL) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage3D (gl_target, + 0, /* level */ + internal_gl_format, + bmp_width, + height, + depth, + 0, + source_gl_format, + source_gl_type, + NULL); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + return FALSE; bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, bmp_width, @@ -327,27 +391,48 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, for (i = 0; i < depth; i++) { - _cogl_bitmap_copy_subregion (source_bmp, - bmp, - 0, image_height * i, - 0, 0, - bmp_width, - height); + if (!_cogl_bitmap_copy_subregion (source_bmp, + bmp, + 0, image_height * i, + 0, 0, + bmp_width, + height, + error)) + { + cogl_object_unref (bmp); + return FALSE; + } data = _cogl_bitmap_gl_bind (bmp, - COGL_BUFFER_ACCESS_READ, 0); + COGL_BUFFER_ACCESS_READ, 0, error); + if (!data) + { + cogl_object_unref (bmp); + return FALSE; + } - GE( ctx, glTexSubImage3D (gl_target, - 0, /* level */ - 0, /* xoffset */ - 0, /* yoffset */ - i, /* zoffset */ - bmp_width, /* width */ - height, /* height */ - 1, /* depth */ - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexSubImage3D (gl_target, + 0, /* level */ + 0, /* xoffset */ + 0, /* yoffset */ + i, /* zoffset */ + bmp_width, /* width */ + height, /* height */ + 1, /* depth */ + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + { + cogl_object_unref (bmp); + _cogl_bitmap_gl_unbind (bmp); + return FALSE; + } _cogl_bitmap_gl_unbind (bmp); } @@ -356,23 +441,37 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, } else { - data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0); + data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); + if (!data) + return FALSE; _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); - GE( ctx, glTexImage3D (gl_target, - 0, /* level */ - internal_gl_format, - bmp_width, - height, - depth, - 0, - source_gl_format, - source_gl_type, - data) ); + /* Clear any GL errors */ + while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) + ; + + ctx->glTexImage3D (gl_target, + 0, /* level */ + internal_gl_format, + bmp_width, + height, + depth, + 0, + source_gl_format, + source_gl_type, + data); + + if (_cogl_gl_util_catch_out_of_memory (ctx, error)) + { + _cogl_bitmap_gl_unbind (source_bmp); + return FALSE; + } _cogl_bitmap_gl_unbind (source_bmp); } + + return TRUE; } /* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h index 5374cad1a..957a19443 100644 --- a/cogl/driver/nop/cogl-texture-2d-nop-private.h +++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h @@ -93,7 +93,7 @@ _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d); void _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d); -void +CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, CoglBitmap *bitmap, int dst_x, @@ -101,7 +101,8 @@ _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, - int height); + int height, + CoglError **error); void _cogl_texture_2d_nop_get_data (CoglTexture2D *tex_2d, diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c index ea4e32197..5118e26da 100644 --- a/cogl/driver/nop/cogl-texture-2d-nop.c +++ b/cogl/driver/nop/cogl-texture-2d-nop.c @@ -135,7 +135,7 @@ _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d) { } -void +CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, CoglBitmap *bitmap, int dst_x, @@ -143,8 +143,10 @@ _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, - int height) + int height, + CoglError **error) { + return TRUE; } void diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c index b7889bc51..d2d8f4cfd 100644 --- a/cogl/winsys/cogl-texture-pixmap-x11.c +++ b/cogl/winsys/cogl-texture-pixmap-x11.c @@ -677,17 +677,22 @@ _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) } static CoglBool -_cogl_texture_pixmap_x11_set_region (CoglTexture *tex, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp) +_cogl_texture_pixmap_x11_set_region (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int dst_width, + int dst_height, + CoglBitmap *bmp, + CoglError **error) { /* This doesn't make much sense for texture from pixmap so it's not supported */ + _cogl_set_error (error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Explicitly setting a region of a TFP texture unsupported"); return FALSE; } diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index 5ccab9e60..fc7821bd4 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -749,6 +749,7 @@ cogl_buffer_usage_hint_get_type cogl-attribute-buffer CoglAttributeBuffer: Buffers of vertex attributes CoglAttributeBuffer +cogl_attribute_buffer_new_with_size cogl_attribute_buffer_new cogl_is_attribute_buffer diff --git a/tests/conform/test-map-buffer-range.c b/tests/conform/test-map-buffer-range.c index 9eb47703a..a223bbc03 100644 --- a/tests/conform/test-map-buffer-range.c +++ b/tests/conform/test-map-buffer-range.c @@ -65,7 +65,8 @@ test_map_buffer_range (void) sizeof (vertex_data[0]) * 2, sizeof (vertex_data[0]), COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD_RANGE); + COGL_BUFFER_MAP_HINT_DISCARD_RANGE, + NULL); /* don't catch errors */ g_assert (data != NULL); data->x = vertex_data[2].x;