Allow propogation of OOM errors to apps

This allows apps to catch out-of-memory errors when allocating textures.

Textures can be pretty huge at times and so it's quite possible for an
application to try and allocate more memory than is available. It's also
very possible that the application can take some action in response to
reduce memory pressure (such as freeing up texture caches perhaps) so
we shouldn't just automatically abort like we do for trivial heap
allocations.

These public functions now take a CoglError argument so applications can
catch out of memory errors:

cogl_buffer_map
cogl_buffer_map_range
cogl_buffer_set_data
cogl_framebuffer_read_pixels_into_bitmap
cogl_pixel_buffer_new
cogl_texture_new_from_data
cogl_texture_new_from_bitmap

Note: we've been quite conservative with how many apis we let throw OOM
CoglErrors since we don't really want to put a burdon on developers to
be checking for errors with every cogl api call. So long as there is
some lower level api for apps to use that let them catch OOM errors
for everything necessary that's enough and we don't have to make more
convenient apis more awkward to use.

The main focus is on bitmaps and texture allocations since they
can be particularly large and prone to failing.

A new cogl_attribute_buffer_new_with_size() function has been added in
case developers need to catch OOM errors when allocating attribute buffers
whereby they can first use _buffer_new_with_size() (which doesn't take a
CoglError) followed by cogl_buffer_set_data() which will lazily allocate
the buffer storage and report OOM errors.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit f7735e141ad537a253b02afa2a8238f96340b978)

Note: since we can't break the API for Cogl 1.x then actually the main
purpose of cherry picking this patch is to keep in-line with changes
on the master branch so that we can easily cherry-pick patches.

All the api changes relating stable apis released on the 1.12 branch
have been reverted as part of cherry-picking this patch so this most
just applies all the internal plumbing changes that enable us to
correctly propagate OOM errors.
This commit is contained in:
Robert Bragg 2012-11-08 17:54:10 +00:00
parent 63db64f426
commit f53fb5e2e0
45 changed files with 1920 additions and 969 deletions

View File

@ -269,8 +269,9 @@ emit_vertex_buffer_geometry (CoglPangoDisplayListNode *node)
n_verts = node->d.texture.rectangles->len * 4; n_verts = node->d.texture.rectangles->len * 4;
buffer buffer
= cogl_attribute_buffer_new (ctx, = cogl_attribute_buffer_new_with_size (ctx,
n_verts * sizeof (CoglVertexP2T2), NULL); n_verts *
sizeof (CoglVertexP2T2));
if ((verts = cogl_buffer_map (COGL_BUFFER (buffer), if ((verts = cogl_buffer_map (COGL_BUFFER (buffer),
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,

View File

@ -60,7 +60,8 @@ struct _CoglAtlasTexture
CoglAtlasTexture * CoglAtlasTexture *
_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat internal_format); CoglPixelFormat internal_format,
CoglError **error);
CoglAtlasTexture * CoglAtlasTexture *
_cogl_atlas_texture_new_with_size (unsigned int width, _cogl_atlas_texture_new_with_size (unsigned int width,

View File

@ -44,6 +44,7 @@
#include "cogl-atlas.h" #include "cogl-atlas.h"
#include "cogl1-context.h" #include "cogl1-context.h"
#include "cogl-sub-texture.h" #include "cogl-sub-texture.h"
#include "cogl-error-private.h"
#include <stdlib.h> #include <stdlib.h>
@ -437,59 +438,65 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglAtlas *atlas = atlas_tex->atlas; CoglAtlas *atlas = atlas_tex->atlas;
/* Copy the central data */ /* Copy the central data */
if (!cogl_texture_set_region_from_bitmap (atlas->texture, if (!_cogl_texture_set_region_from_bitmap (atlas->texture,
src_x, src_y, src_x, src_y,
dst_x + atlas_tex->rectangle.x + 1, dst_x + atlas_tex->rectangle.x + 1,
dst_y + atlas_tex->rectangle.y + 1, dst_y + atlas_tex->rectangle.y + 1,
dst_width, dst_width,
dst_height, dst_height,
bmp)) bmp,
error))
return FALSE; return FALSE;
/* Update the left edge pixels */ /* Update the left edge pixels */
if (dst_x == 0 && if (dst_x == 0 &&
!cogl_texture_set_region_from_bitmap (atlas->texture, !_cogl_texture_set_region_from_bitmap (atlas->texture,
src_x, src_y, src_x, src_y,
atlas_tex->rectangle.x, atlas_tex->rectangle.x,
dst_y + atlas_tex->rectangle.y + 1, dst_y + atlas_tex->rectangle.y + 1,
1, dst_height, 1, dst_height,
bmp)) bmp,
error))
return FALSE; return FALSE;
/* Update the right edge pixels */ /* Update the right edge pixels */
if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && if (dst_x + dst_width == atlas_tex->rectangle.width - 2 &&
!cogl_texture_set_region_from_bitmap (atlas->texture, !_cogl_texture_set_region_from_bitmap (atlas->texture,
src_x + dst_width - 1, src_y, src_x + dst_width - 1, src_y,
atlas_tex->rectangle.x + atlas_tex->rectangle.x +
atlas_tex->rectangle.width - 1, atlas_tex->rectangle.width - 1,
dst_y + atlas_tex->rectangle.y + 1, dst_y + atlas_tex->rectangle.y + 1,
1, dst_height, 1, dst_height,
bmp)) bmp,
error))
return FALSE; return FALSE;
/* Update the top edge pixels */ /* Update the top edge pixels */
if (dst_y == 0 && if (dst_y == 0 &&
!cogl_texture_set_region_from_bitmap (atlas->texture, !_cogl_texture_set_region_from_bitmap (atlas->texture,
src_x, src_y, src_x, src_y,
dst_x + atlas_tex->rectangle.x + 1, dst_x + atlas_tex->rectangle.x + 1,
atlas_tex->rectangle.y, atlas_tex->rectangle.y,
dst_width, 1, dst_width, 1,
bmp)) bmp,
error))
return FALSE; return FALSE;
/* Update the bottom edge pixels */ /* Update the bottom edge pixels */
if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && if (dst_y + dst_height == atlas_tex->rectangle.height - 2 &&
!cogl_texture_set_region_from_bitmap (atlas->texture, !_cogl_texture_set_region_from_bitmap (atlas->texture,
src_x, src_y + dst_height - 1, src_x, src_y + dst_height - 1,
dst_x + atlas_tex->rectangle.x + 1, dst_x + atlas_tex->rectangle.x + 1,
atlas_tex->rectangle.y + atlas_tex->rectangle.y +
atlas_tex->rectangle.height - 1, atlas_tex->rectangle.height - 1,
dst_width, 1, dst_width, 1,
bmp)) bmp,
error))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -497,7 +504,8 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
static CoglBitmap * static CoglBitmap *
_cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex, _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglPixelFormat internal_format; CoglPixelFormat internal_format;
CoglBitmap *converted_bmp; CoglBitmap *converted_bmp;
@ -519,7 +527,8 @@ _cogl_atlas_texture_prepare_for_upload (CoglAtlasTexture *atlas_tex,
NULL, /* dst_format_out */ NULL, /* dst_format_out */
NULL, /* glintformat */ NULL, /* glintformat */
NULL, /* glformat */ NULL, /* glformat */
NULL /* gltype */); NULL, /* gltype */
error);
if (converted_bmp == NULL) if (converted_bmp == NULL)
return NULL; return NULL;
@ -547,9 +556,10 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
@ -560,14 +570,18 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
CoglBool ret; CoglBool ret;
bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex, bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex,
bmp); bmp,
error);
if (!bmp)
return FALSE;
/* Upload the data ignoring the premult bit */ /* Upload the data ignoring the premult bit */
ret = _cogl_atlas_texture_set_region_with_border (atlas_tex, ret = _cogl_atlas_texture_set_region_with_border (atlas_tex,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
bmp); bmp,
error);
cogl_object_unref (bmp); cogl_object_unref (bmp);
@ -575,11 +589,12 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
} }
else else
/* Otherwise we can just forward on to the sub texture */ /* Otherwise we can just forward on to the sub texture */
return cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture, return _cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
bmp); bmp,
error);
} }
static CoglPixelFormat static CoglPixelFormat
@ -729,7 +744,8 @@ _cogl_atlas_texture_new_with_size (unsigned int width,
CoglAtlasTexture * CoglAtlasTexture *
_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat internal_format) CoglPixelFormat internal_format,
CoglError **error)
{ {
CoglAtlasTexture *atlas_tex; CoglAtlasTexture *atlas_tex;
CoglBitmap *dst_bmp; CoglBitmap *dst_bmp;
@ -750,11 +766,17 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
flags, internal_format); flags, internal_format);
if (atlas_tex == NULL) if (atlas_tex == NULL)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Texture type not compatible with atlas");
return NULL; return NULL;
}
dst_bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex, dst_bmp = _cogl_atlas_texture_prepare_for_upload (atlas_tex,
bmp); bmp,
error);
if (dst_bmp == NULL) if (dst_bmp == NULL)
{ {
cogl_object_unref (atlas_tex); 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 /* Defer to set_region so that we can share the code for copying the
edge pixels to the border. */ edge pixels to the border. */
_cogl_atlas_texture_set_region_with_border (atlas_tex, if (!_cogl_atlas_texture_set_region_with_border (atlas_tex,
0, /* src_x */ 0, /* src_x */
0, /* src_y */ 0, /* src_y */
0, /* dst_x */ 0, /* dst_x */
0, /* dst_y */ 0, /* dst_y */
bmp_width, /* dst_width */ bmp_width, /* dst_width */
bmp_height, /* dst_height */ bmp_height, /* dst_height */
dst_bmp); dst_bmp,
error))
{
cogl_object_unref (dst_bmp);
cogl_object_unref (atlas_tex);
return NULL;
}
cogl_object_unref (dst_bmp); cogl_object_unref (dst_bmp);

View File

@ -39,28 +39,50 @@ static void _cogl_attribute_buffer_free (CoglAttributeBuffer *array);
COGL_BUFFER_DEFINE (AttributeBuffer, attribute_buffer); COGL_BUFFER_DEFINE (AttributeBuffer, attribute_buffer);
CoglAttributeBuffer * CoglAttributeBuffer *
cogl_attribute_buffer_new (CoglContext *context, cogl_attribute_buffer_new_with_size (CoglContext *context,
size_t bytes, size_t bytes)
const void *data)
{ {
CoglAttributeBuffer *array = g_slice_new (CoglAttributeBuffer); CoglAttributeBuffer *buffer = g_slice_new (CoglAttributeBuffer);
/* parent's constructor */ /* parent's constructor */
_cogl_buffer_initialize (COGL_BUFFER (array), _cogl_buffer_initialize (COGL_BUFFER (buffer),
context, context,
bytes, bytes,
COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER,
COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER, COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER,
COGL_BUFFER_UPDATE_HINT_STATIC); 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) if (data)
cogl_buffer_set_data (COGL_BUFFER (array), _cogl_buffer_set_data (COGL_BUFFER (buffer),
0, 0,
data, data,
bytes); bytes,
return array; NULL);
return buffer;
} }
static void static void

View File

@ -50,18 +50,57 @@ COGL_BEGIN_DECLS
#define COGL_ATTRIBUTE_BUFFER(buffer) ((CoglAttributeBuffer *)(buffer)) #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: * cogl_attribute_buffer_new:
* @context: A #CoglContext * @context: A #CoglContext
* @bytes: The number of bytes to allocate for vertex attribute data. * @bytes: The number of bytes to allocate for vertex attribute data.
* @data: An optional pointer to vertex data to upload immediately. * @data: An optional pointer to vertex data to upload immediately.
* *
* Declares a new #CoglAttributeBuffer of @size bytes to contain arrays of vertex * Describes a new #CoglAttributeBuffer of @size bytes to contain
* attribute data. Once declared, data can be set using cogl_buffer_set_data() * arrays of vertex attribute data and also uploads @size bytes read
* or by mapping it into the application's address space using cogl_buffer_map(). * from @data to the new buffer.
* *
* If @data isn't %NULL then @size bytes will be read from @data and * You should never pass a %NULL data pointer.
* immediately copied into the new buffer. *
* <note>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.</note>
*
* <note>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().</note>
*
* Return value: A newly allocated #CoglAttributeBuffer (never %NULL)
* *
* Since: 1.4 * Since: 1.4
* Stability: Unstable * Stability: Unstable

View File

@ -348,7 +348,8 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format)
CoglBool CoglBool
_cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
CoglBitmap *dst_bmp) CoglBitmap *dst_bmp,
CoglError **error)
{ {
uint8_t *src_data; uint8_t *src_data;
uint8_t *dst_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, if (!_cogl_bitmap_copy_subregion (src_bmp, dst_bmp,
0, 0, /* src_x / src_y */ 0, 0, /* src_x / src_y */
0, 0, /* dst_x / dst_y */ 0, 0, /* dst_x / dst_y */
width, height)) width, height,
error))
return FALSE; return FALSE;
if (need_premult) if (need_premult)
{ {
if ((dst_format & COGL_PREMULT_BIT)) if ((dst_format & COGL_PREMULT_BIT))
{ {
if (!_cogl_bitmap_premult (dst_bmp)) if (!_cogl_bitmap_premult (dst_bmp, error))
return FALSE; return FALSE;
} }
else else
{ {
if (!_cogl_bitmap_unpremult (dst_bmp)) if (!_cogl_bitmap_unpremult (dst_bmp, error))
return FALSE; return FALSE;
} }
} }
@ -408,12 +410,13 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
return TRUE; 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) if (src_data == NULL)
return FALSE; return FALSE;
dst_data = _cogl_bitmap_map (dst_bmp, dst_data = _cogl_bitmap_map (dst_bmp,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
error);
if (dst_data == NULL) if (dst_data == NULL)
{ {
_cogl_bitmap_unmap (src_bmp); _cogl_bitmap_unmap (src_bmp);
@ -472,7 +475,8 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
CoglBitmap * CoglBitmap *
_cogl_bitmap_convert (CoglBitmap *src_bmp, _cogl_bitmap_convert (CoglBitmap *src_bmp,
CoglPixelFormat dst_format) CoglPixelFormat dst_format,
CoglError **error)
{ {
CoglBitmap *dst_bmp; CoglBitmap *dst_bmp;
int width, height; int width, height;
@ -486,7 +490,7 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
width, height, width, height,
dst_format); 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); cogl_object_unref (dst_bmp);
return NULL; return NULL;
@ -496,7 +500,8 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
} }
CoglBool CoglBool
_cogl_bitmap_unpremult (CoglBitmap *bmp) _cogl_bitmap_unpremult (CoglBitmap *bmp,
CoglError **error)
{ {
uint8_t *p, *data; uint8_t *p, *data;
uint16_t *tmp_row; uint16_t *tmp_row;
@ -513,7 +518,8 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp)
if ((data = _cogl_bitmap_map (bmp, if ((data = _cogl_bitmap_map (bmp,
COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_READ |
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
0)) == NULL) 0,
error)) == NULL)
return FALSE; return FALSE;
/* If we can't directly unpremult the data inline then we'll /* If we can't directly unpremult the data inline then we'll
@ -562,7 +568,8 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp)
} }
CoglBool CoglBool
_cogl_bitmap_premult (CoglBitmap *bmp) _cogl_bitmap_premult (CoglBitmap *bmp,
CoglError **error)
{ {
uint8_t *p, *data; uint8_t *p, *data;
uint16_t *tmp_row; uint16_t *tmp_row;
@ -579,7 +586,8 @@ _cogl_bitmap_premult (CoglBitmap *bmp)
if ((data = _cogl_bitmap_map (bmp, if ((data = _cogl_bitmap_map (bmp,
COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_READ |
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
0)) == NULL) 0,
error)) == NULL)
return FALSE; return FALSE;
/* If we can't directly premult the data inline then we'll allocate /* If we can't directly premult the data inline then we'll allocate

View File

@ -100,11 +100,13 @@ _cogl_bitmap_new_shared (CoglBitmap *shared_bmp,
CoglBitmap * CoglBitmap *
_cogl_bitmap_convert (CoglBitmap *bmp, _cogl_bitmap_convert (CoglBitmap *bmp,
CoglPixelFormat dst_format); CoglPixelFormat dst_format,
CoglError **error);
CoglBool CoglBool
_cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
CoglBitmap *dst_bmp); CoglBitmap *dst_bmp,
CoglError **error);
CoglBitmap * CoglBitmap *
_cogl_bitmap_from_file (CoglContext *ctx, _cogl_bitmap_from_file (CoglContext *ctx,
@ -120,14 +122,17 @@ _cogl_android_bitmap_new_from_asset (CoglContext *ctx,
#endif #endif
CoglBool CoglBool
_cogl_bitmap_unpremult (CoglBitmap *dst_bmp); _cogl_bitmap_unpremult (CoglBitmap *dst_bmp,
CoglError **error);
CoglBool CoglBool
_cogl_bitmap_premult (CoglBitmap *dst_bmp); _cogl_bitmap_premult (CoglBitmap *dst_bmp,
CoglError **error);
CoglBool CoglBool
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, _cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
CoglPixelFormat dst_format); CoglPixelFormat dst_format,
CoglError **error);
CoglBool CoglBool
_cogl_bitmap_copy_subregion (CoglBitmap *src, _cogl_bitmap_copy_subregion (CoglBitmap *src,
@ -137,11 +142,13 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
int dst_x, int dst_x,
int dst_y, int dst_y,
int width, int width,
int height); int height,
CoglError **error);
/* Creates a deep copy of the source bitmap */ /* Creates a deep copy of the source bitmap */
CoglBitmap * CoglBitmap *
_cogl_bitmap_copy (CoglBitmap *src_bmp); _cogl_bitmap_copy (CoglBitmap *src_bmp,
CoglError **error);
CoglBool CoglBool
_cogl_bitmap_get_size_from_file (const char *filename, _cogl_bitmap_get_size_from_file (const char *filename,
@ -163,7 +170,8 @@ _cogl_bitmap_set_format (CoglBitmap *bitmap,
uint8_t * uint8_t *
_cogl_bitmap_map (CoglBitmap *bitmap, _cogl_bitmap_map (CoglBitmap *bitmap,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
void void
_cogl_bitmap_unmap (CoglBitmap *bitmap); _cogl_bitmap_unmap (CoglBitmap *bitmap);
@ -180,7 +188,8 @@ _cogl_bitmap_unmap (CoglBitmap *bitmap);
uint8_t * uint8_t *
_cogl_bitmap_gl_bind (CoglBitmap *bitmap, _cogl_bitmap_gl_bind (CoglBitmap *bitmap,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
void void
_cogl_bitmap_gl_unbind (CoglBitmap *bitmap); _cogl_bitmap_gl_unbind (CoglBitmap *bitmap);

View File

@ -33,6 +33,7 @@
#include "cogl-pixel-buffer.h" #include "cogl-pixel-buffer.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-buffer-gl-private.h" #include "cogl-buffer-gl-private.h"
#include "cogl-error-private.h"
#include <string.h> #include <string.h>
@ -57,26 +58,28 @@ _cogl_bitmap_free (CoglBitmap *bmp)
CoglBool CoglBool
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp, _cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
CoglPixelFormat dst_format) CoglPixelFormat dst_format,
CoglError **error)
{ {
/* Do we need to unpremultiply? */ /* Do we need to unpremultiply? */
if ((bmp->format & COGL_PREMULT_BIT) > 0 && if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
(dst_format & COGL_PREMULT_BIT) == 0 && (dst_format & COGL_PREMULT_BIT) == 0 &&
COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format)) COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format))
return _cogl_bitmap_unpremult (bmp); return _cogl_bitmap_unpremult (bmp, error);
/* Do we need to premultiply? */ /* Do we need to premultiply? */
if ((bmp->format & COGL_PREMULT_BIT) == 0 && if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (bmp->format) && COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (bmp->format) &&
(dst_format & COGL_PREMULT_BIT) > 0) (dst_format & COGL_PREMULT_BIT) > 0)
/* Try premultiplying using imaging library */ /* Try premultiplying using imaging library */
return _cogl_bitmap_premult (bmp); return _cogl_bitmap_premult (bmp, error);
return TRUE; return TRUE;
} }
CoglBitmap * CoglBitmap *
_cogl_bitmap_copy (CoglBitmap *src_bmp) _cogl_bitmap_copy (CoglBitmap *src_bmp,
CoglError **error)
{ {
CoglBitmap *dst_bmp; CoglBitmap *dst_bmp;
CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp); CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
@ -88,11 +91,16 @@ _cogl_bitmap_copy (CoglBitmap *src_bmp)
width, height, width, height,
src_format); src_format);
_cogl_bitmap_copy_subregion (src_bmp, if (!_cogl_bitmap_copy_subregion (src_bmp,
dst_bmp, dst_bmp,
0, 0, /* src_x/y */ 0, 0, /* src_x/y */
0, 0, /* dst_x/y */ 0, 0, /* dst_x/y */
width, height); width, height,
error))
{
cogl_object_unref (dst_bmp);
return NULL;
}
return dst_bmp; return dst_bmp;
} }
@ -105,7 +113,8 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
int dst_x, int dst_x,
int dst_y, int dst_y,
int width, int width,
int height) int height,
CoglError **error)
{ {
uint8_t *srcdata; uint8_t *srcdata;
uint8_t *dstdata; uint8_t *dstdata;
@ -114,19 +123,21 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
CoglBool succeeded = FALSE; CoglBool succeeded = FALSE;
/* Intended only for fast copies when format is equal! */ /* Intended only for fast copies when format is equal! */
g_assert ((src->format & ~COGL_PREMULT_BIT) == _COGL_RETURN_VAL_IF_FAIL ((src->format & ~COGL_PREMULT_BIT) ==
(dst->format & ~COGL_PREMULT_BIT)); (dst->format & ~COGL_PREMULT_BIT),
FALSE);
bpp = _cogl_pixel_format_get_bytes_per_pixel (src->format); 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; srcdata += src_y * src->rowstride + src_x * bpp;
dstdata += dst_y * dst->rowstride + dst_x * bpp; dstdata += dst_y * dst->rowstride + dst_x * bpp;
for (line=0; line<height; ++line) for (line = 0; line < height; ++line)
{ {
memcpy (dstdata, srcdata, width * bpp); memcpy (dstdata, srcdata, width * bpp);
srcdata += src->rowstride; srcdata += src->rowstride;
@ -271,17 +282,18 @@ cogl_bitmap_new_with_size (CoglContext *context,
unsigned int rowstride; unsigned int rowstride;
/* creating a buffer to store "any" format does not make sense */ /* creating a buffer to store "any" format does not make sense */
if (G_UNLIKELY (format == COGL_PIXEL_FORMAT_ANY)) _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
return NULL;
/* for now we fallback to cogl_pixel_buffer_new, later, we could ask /* for now we fallback to cogl_pixel_buffer_new, later, we could ask
* libdrm a tiled buffer for instance */ * libdrm a tiled buffer for instance */
rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); 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)) _COGL_RETURN_VAL_IF_FAIL (pixel_buffer != NULL, NULL);
return NULL;
bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer), bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer),
format, format,
@ -359,19 +371,21 @@ cogl_bitmap_error_quark (void)
uint8_t * uint8_t *
_cogl_bitmap_map (CoglBitmap *bitmap, _cogl_bitmap_map (CoglBitmap *bitmap,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints,
CoglError **error)
{ {
/* Divert to another bitmap if this data is shared */ /* Divert to another bitmap if this data is shared */
if (bitmap->shared_bmp) 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); g_assert (!bitmap->mapped);
if (bitmap->buffer) if (bitmap->buffer)
{ {
uint8_t *data = cogl_buffer_map (bitmap->buffer, uint8_t *data = _cogl_buffer_map (bitmap->buffer,
access, access,
hints); hints,
error);
COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This " COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This "
"usually means that some conversion on the pixel array is " "usually means that some conversion on the pixel array is "
@ -414,21 +428,23 @@ _cogl_bitmap_unmap (CoglBitmap *bitmap)
uint8_t * uint8_t *
_cogl_bitmap_gl_bind (CoglBitmap *bitmap, _cogl_bitmap_gl_bind (CoglBitmap *bitmap,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints,
CoglError **error)
{ {
uint8_t *ptr; uint8_t *ptr;
CoglError *internal_error = NULL;
/* Divert to another bitmap if this data is shared */ /* Divert to another bitmap if this data is shared */
if (bitmap->shared_bmp) 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 /* If the bitmap wasn't created from a buffer then the
implementation of bind is the same as map */ implementation of bind is the same as map */
if (bitmap->buffer == NULL) 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) if (data)
bitmap->bound = TRUE; bitmap->bound = TRUE;
return data; return data;
@ -438,15 +454,29 @@ _cogl_bitmap_gl_bind (CoglBitmap *bitmap,
if (access == COGL_BUFFER_ACCESS_READ) if (access == COGL_BUFFER_ACCESS_READ)
ptr = _cogl_buffer_gl_bind (bitmap->buffer, 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) else if (access == COGL_BUFFER_ACCESS_WRITE)
ptr = _cogl_buffer_gl_bind (bitmap->buffer, ptr = _cogl_buffer_gl_bind (bitmap->buffer,
COGL_BUFFER_BIND_TARGET_PIXEL_PACK); COGL_BUFFER_BIND_TARGET_PIXEL_PACK,
&internal_error);
else else
{
ptr = NULL;
g_assert_not_reached (); 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 */ /* The data pointer actually stores the offset */
return GPOINTER_TO_INT (bitmap->data) + ptr; return ptr + GPOINTER_TO_INT (bitmap->data);
} }
void void

View File

@ -292,6 +292,7 @@ _cogl_blit_get_tex_data_blit (CoglBlitData *data,
data->format, data->format,
data->src_width * data->bpp, data->src_width * data->bpp,
data->image_data); data->image_data);
/* TODO: support chaining up errors during the blit */
} }
static void static void

View File

@ -45,14 +45,16 @@ struct _CoglBufferVtable
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
void (* unmap) (CoglBuffer *buffer); void (* unmap) (CoglBuffer *buffer);
CoglBool (* set_data) (CoglBuffer *buffer, CoglBool (* set_data) (CoglBuffer *buffer,
unsigned int offset, unsigned int offset,
const void *data, const void *data,
unsigned int size); unsigned int size,
CoglError **error);
}; };
typedef enum _CoglBufferFlags typedef enum _CoglBufferFlags
@ -137,6 +139,19 @@ _cogl_buffer_immutable_ref (CoglBuffer *buffer);
void void
_cogl_buffer_immutable_unref (CoglBuffer *buffer); _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 /* 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 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 contents. If the map fails then it will fallback to writing to a

View File

@ -83,7 +83,8 @@ malloc_map_range (CoglBuffer *buffer,
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints,
CoglError **error)
{ {
buffer->flags |= COGL_BUFFER_FLAG_MAPPED; buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
return buffer->data + offset; return buffer->data + offset;
@ -99,7 +100,8 @@ static CoglBool
malloc_set_data (CoglBuffer *buffer, malloc_set_data (CoglBuffer *buffer,
unsigned int offset, unsigned int offset,
const void *data, const void *data,
unsigned int size) unsigned int size,
CoglError **error)
{ {
memcpy (buffer->data + offset, data, size); memcpy (buffer->data + offset, data, size);
return TRUE; return TRUE;
@ -213,14 +215,29 @@ warn_about_midscene_changes (void)
} }
} }
void *
_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, error);
}
void * void *
cogl_buffer_map (CoglBuffer *buffer, cogl_buffer_map (CoglBuffer *buffer,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints)
{ {
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); CoglError *ignore_error = NULL;
void *ptr =
return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints); cogl_buffer_map_range (buffer, 0, buffer->size, access, hints,
&ignore_error);
if (!ptr)
cogl_error_free (ignore_error);
return ptr;
} }
void * void *
@ -228,21 +245,21 @@ cogl_buffer_map_range (CoglBuffer *buffer,
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints,
CoglError **error)
{ {
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); _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)) if (G_UNLIKELY (buffer->immutable_ref))
warn_about_midscene_changes (); warn_about_midscene_changes ();
if (buffer->flags & COGL_BUFFER_FLAG_MAPPED)
return buffer->data;
buffer->data = buffer->vtable.map_range (buffer, buffer->data = buffer->vtable.map_range (buffer,
offset, offset,
size, size,
access, access,
hints); hints,
error);
return buffer->data; return buffer->data;
} }
@ -272,6 +289,7 @@ _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer,
{ {
CoglContext *ctx = buffer->context; CoglContext *ctx = buffer->context;
void *ret; void *ret;
CoglError *ignore_error = NULL;
_COGL_RETURN_VAL_IF_FAIL (!ctx->buffer_map_fallback_in_use, NULL); _COGL_RETURN_VAL_IF_FAIL (!ctx->buffer_map_fallback_in_use, NULL);
@ -281,12 +299,14 @@ _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer,
offset, offset,
size, size,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
&ignore_error);
if (ret) if (ret)
return ret; return ret;
else
{ cogl_error_free (ignore_error);
/* If the map fails then we'll use a temporary buffer to fill /* 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 data and then upload it using cogl_buffer_set_data when
the buffer is unmapped. The temporary buffer is shared to the buffer is unmapped. The temporary buffer is shared to
@ -297,7 +317,6 @@ _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer,
buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK; buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK;
return ctx->buffer_map_fallback_array->data; return ctx->buffer_map_fallback_array->data;
}
} }
void void
@ -311,29 +330,59 @@ _cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer)
if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK)) if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK))
{ {
cogl_buffer_set_data (buffer, /* 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_offset,
ctx->buffer_map_fallback_array->data, ctx->buffer_map_fallback_array->data,
ctx->buffer_map_fallback_array->len); ctx->buffer_map_fallback_array->len,
NULL);
buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK; buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK;
} }
else else
cogl_buffer_unmap (buffer); 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 CoglBool
cogl_buffer_set_data (CoglBuffer *buffer, cogl_buffer_set_data (CoglBuffer *buffer,
size_t offset, size_t offset,
const void *data, const void *data,
size_t size) size_t size)
{ {
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), FALSE); CoglError *ignore_error = NULL;
_COGL_RETURN_VAL_IF_FAIL ((offset + size) <= buffer->size, FALSE); CoglBool status =
_cogl_buffer_set_data (buffer, offset, data, size, &ignore_error);
if (G_UNLIKELY (buffer->immutable_ref)) if (!status)
warn_about_midscene_changes (); cogl_error_free (ignore_error);
return status;
return buffer->vtable.set_data (buffer, offset, data, size);
} }
CoglBuffer * CoglBuffer *

View File

@ -33,6 +33,7 @@
#define __COGL_BUFFER_H__ #define __COGL_BUFFER_H__
#include <cogl/cogl-types.h> #include <cogl/cogl-types.h>
#include <cogl/cogl-error.h>
COGL_BEGIN_DECLS COGL_BEGIN_DECLS
@ -62,6 +63,25 @@ COGL_BEGIN_DECLS
typedef struct _CoglBuffer CoglBuffer; 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: * cogl_is_buffer:
* @object: a buffer object * @object: a buffer object
@ -219,6 +239,7 @@ cogl_buffer_map (CoglBuffer *buffer,
* @access: how the mapped buffer will be used by the application * @access: how the mapped buffer will be used by the application
* @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how * @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how
* the data will be modified once mapped. * 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 * Maps a sub-region of the buffer into the application's address space
* for direct access. * for direct access.
@ -246,7 +267,8 @@ cogl_buffer_map_range (CoglBuffer *buffer,
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
/** /**
* cogl_buffer_unmap: * cogl_buffer_unmap:

View File

@ -190,8 +190,11 @@ struct _CoglDriverVtable
/* Initialize the specified region of storage of the given texture /* Initialize the specified region of storage of the given texture
* with the contents of the specified bitmap region * 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, (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d,
CoglBitmap *bitmap, CoglBitmap *bitmap,
int dst_x, int dst_x,
@ -199,7 +202,8 @@ struct _CoglDriverVtable
int src_x, int src_x,
int src_y, int src_y,
int width, int width,
int height); int height,
CoglError **error);
/* Reads back the full contents of the given texture and write it to /* Reads back the full contents of the given texture and write it to
* @data in the given @format and with the given @rowstride. * @data in the given @format and with the given @rowstride.
@ -244,7 +248,8 @@ struct _CoglDriverVtable
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
/* Unmaps a buffer */ /* Unmaps a buffer */
void void
@ -256,7 +261,8 @@ struct _CoglDriverVtable
(* buffer_set_data) (CoglBuffer *buffer, (* buffer_set_data) (CoglBuffer *buffer,
unsigned int offset, unsigned int offset,
const void *data, const void *data,
unsigned int size); unsigned int size,
CoglError **error);
}; };
#endif /* __COGL_DRIVER_H */ #endif /* __COGL_DRIVER_H */

View File

@ -39,6 +39,10 @@ _cogl_set_error_literal (CoglError **error,
int code, int code,
const char *message); const char *message);
void
_cogl_propogate_error (CoglError **dest,
CoglError *src);
void void
_cogl_propogate_gerror (CoglError **dest, _cogl_propogate_gerror (CoglError **dest,
GError *src); GError *src);

View File

@ -99,11 +99,18 @@ _cogl_set_error_literal (CoglError **error,
} }
void void
_cogl_propogate_gerror (CoglError **dest, _cogl_propogate_error (CoglError **dest,
GError *src) CoglError *src)
{ {
_COGL_RETURN_IF_FAIL (src != NULL); _COGL_RETURN_IF_FAIL (src != NULL);
_cogl_set_error_literal (dest, src->domain, src->code, src->message); _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);
} }

View File

@ -453,5 +453,12 @@ _cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer)
return projection_stack->last_entry; 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 */ #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */

View File

@ -1333,6 +1333,7 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
y < framebuffer->clear_clip_y1) y < framebuffer->clear_clip_y1)
{ {
uint8_t *pixel; uint8_t *pixel;
CoglError *ignore_error = NULL;
/* we currently only care about cases where the premultiplied or /* we currently only care about cases where the premultiplied or
* unpremultipled colors are equivalent... */ * unpremultipled colors are equivalent... */
@ -1341,9 +1342,13 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
pixel = _cogl_bitmap_map (bitmap, pixel = _cogl_bitmap_map (bitmap,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
&ignore_error);
if (pixel == NULL) if (pixel == NULL)
{
cogl_error_free (ignore_error);
return FALSE; return FALSE;
}
pixel[0] = framebuffer->clear_color_red * 255.0; pixel[0] = framebuffer->clear_color_red * 255.0;
pixel[1] = framebuffer->clear_color_green * 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 x,
int y, int y,
CoglReadPixelsFlags source, CoglReadPixelsFlags source,
CoglBitmap *bitmap) CoglBitmap *bitmap,
CoglError **error)
{ {
CoglContext *ctx; CoglContext *ctx;
CoglPixelFormat format; CoglPixelFormat format;
@ -1371,6 +1377,8 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
int width; int width;
int height; int height;
CoglBool res; 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 (source & COGL_READ_PIXELS_COLOR_BUFFER, FALSE);
_COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE);
@ -1382,39 +1390,38 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
format = cogl_bitmap_get_format (bitmap); format = cogl_bitmap_get_format (bitmap);
pbo = cogl_bitmap_new_with_size (ctx, width, height, format); 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 /* Read into the pbo. We need to disable the flipping because the
blit fast path in the driver does not work with blit fast path in the driver does not work with
GL_PACK_INVERT_MESA is set */ GL_PACK_INVERT_MESA is set */
res = cogl_framebuffer_read_pixels_into_bitmap (framebuffer, res = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
x, y, x, y,
source | source |
COGL_READ_PIXELS_NO_FLIP, COGL_READ_PIXELS_NO_FLIP,
pbo); pbo,
error);
if (res) if (!res)
{ {
uint8_t *dst; cogl_object_unref (pbo);
return FALSE;
}
/* Copy the pixels back into application's buffer */ /* Copy the pixels back into application's buffer */
dst = _cogl_bitmap_map (bitmap, dst = _cogl_bitmap_map (bitmap,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
error);
if (dst == NULL) if (!dst)
res = FALSE;
else
{ {
const uint8_t *src; cogl_object_unref (pbo);
return FALSE;
}
src = _cogl_bitmap_map (pbo, src = _cogl_bitmap_map (pbo,
COGL_BUFFER_ACCESS_READ, COGL_BUFFER_ACCESS_READ,
0 /* hints */); 0, /* hints */
if (src == NULL) error);
res = FALSE; if (src)
else
{ {
int src_rowstride = cogl_bitmap_get_rowstride (pbo); int src_rowstride = cogl_bitmap_get_rowstride (pbo);
int dst_rowstride = cogl_bitmap_get_rowstride (bitmap); int dst_rowstride = cogl_bitmap_get_rowstride (bitmap);
@ -1439,10 +1446,10 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
_cogl_bitmap_unmap (pbo); _cogl_bitmap_unmap (pbo);
} }
else
res = FALSE;
_cogl_bitmap_unmap (bitmap); _cogl_bitmap_unmap (bitmap);
}
}
cogl_object_unref (pbo); cogl_object_unref (pbo);
@ -1450,11 +1457,12 @@ _cogl_framebuffer_slow_read_pixels_workaround (CoglFramebuffer *framebuffer,
} }
CoglBool CoglBool
cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, _cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
int x, int x,
int y, int y,
CoglReadPixelsFlags source, CoglReadPixelsFlags source,
CoglBitmap *bitmap) CoglBitmap *bitmap,
CoglError **error)
{ {
CoglContext *ctx; CoglContext *ctx;
int framebuffer_height; int framebuffer_height;
@ -1466,11 +1474,13 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
CoglBool pack_invert_set; CoglBool pack_invert_set;
int width; int width;
int height; 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 (source & COGL_READ_PIXELS_COLOR_BUFFER, FALSE);
_COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), 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; return FALSE;
ctx = cogl_framebuffer_get_context (framebuffer); ctx = cogl_framebuffer_get_context (framebuffer);
@ -1515,10 +1525,17 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
(width > 8 || height > 8) && (width > 8 || height > 8) &&
(format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 && (format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 &&
cogl_bitmap_get_buffer (bitmap) == NULL) cogl_bitmap_get_buffer (bitmap) == NULL)
return _cogl_framebuffer_slow_read_pixels_workaround (framebuffer, {
if (_cogl_framebuffer_slow_read_pixels_workaround (framebuffer,
x, y, x, y,
source, source,
bitmap); bitmap,
&ignore_error))
return TRUE;
else
cogl_error_free (ignore_error);
}
/* make sure any batched primitives get emitted to the GL driver /* make sure any batched primitives get emitted to the GL driver
* before issuing our read pixels... * before issuing our read pixels...
@ -1578,7 +1595,7 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
CoglPixelFormat read_format; CoglPixelFormat read_format;
int bpp, rowstride; int bpp, rowstride;
uint8_t *tmp_data; uint8_t *tmp_data;
int succeeded; CoglBool succeeded;
if ((ctx->private_feature_flags & if ((ctx->private_feature_flags &
COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT)) COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT))
@ -1605,9 +1622,13 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
width, width,
bpp); 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, tmp_data = _cogl_bitmap_gl_bind (tmp_bmp,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
NULL);
GE( ctx, glReadPixels (x, y, width, height, GE( ctx, glReadPixels (x, y, width, height,
gl_format, gl_type, gl_format, gl_type,
@ -1615,12 +1636,12 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
_cogl_bitmap_gl_unbind (tmp_bmp); _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); cogl_object_unref (tmp_bmp);
if (!succeeded) if (!succeeded)
return FALSE; goto EXIT;
} }
else else
{ {
@ -1629,6 +1650,7 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
int bpp, rowstride; int bpp, rowstride;
CoglBool succeeded = FALSE; CoglBool succeeded = FALSE;
uint8_t *pixels; uint8_t *pixels;
CoglError *internal_error = NULL;
rowstride = cogl_bitmap_get_rowstride (bitmap); 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, pixels = _cogl_bitmap_gl_bind (shared_bmp,
COGL_BUFFER_ACCESS_WRITE, 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, GE( ctx, glReadPixels (x, y,
width, height, width, height,
@ -1670,21 +1702,15 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
/* Convert to the premult format specified by the caller /* Convert to the premult format specified by the caller
in-place. This will do nothing if the premult status is already in-place. This will do nothing if the premult status is already
correct. */ correct. */
if (_cogl_bitmap_convert_premult_status (shared_bmp, format)) if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error))
succeeded = TRUE; succeeded = TRUE;
cogl_object_unref (shared_bmp); cogl_object_unref (shared_bmp);
if (!succeeded) 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 /* NB: All offscreen rendering is done upside down so there is no need
* to flip in this case... */ * to flip in this case... */
if (!cogl_is_offscreen (framebuffer) && if (!cogl_is_offscreen (framebuffer) &&
@ -1699,10 +1725,11 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
pixels = _cogl_bitmap_map (bitmap, pixels = _cogl_bitmap_map (bitmap,
COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_READ |
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
0 /* hints */); 0, /* hints */
error);
if (pixels == NULL) if (pixels == NULL)
return FALSE; goto EXIT;
temprow = g_alloca (rowstride * sizeof (uint8_t)); temprow = g_alloca (rowstride * sizeof (uint8_t));
@ -1724,7 +1751,34 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
_cogl_bitmap_unmap (bitmap); _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 CoglBool
@ -1745,10 +1799,17 @@ cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer,
format, format,
bpp * width, /* rowstride */ bpp * width, /* rowstride */
pixels); pixels);
ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
/* 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, x, y,
COGL_READ_PIXELS_COLOR_BUFFER, COGL_READ_PIXELS_COLOR_BUFFER,
bitmap); bitmap,
NULL);
cogl_object_unref (bitmap); cogl_object_unref (bitmap);
return ret; return ret;
@ -2378,8 +2439,9 @@ get_wire_line_indices (CoglContext *ctx,
if (user_indices) if (user_indices)
{ {
index_buffer = cogl_indices_get_buffer (user_indices); index_buffer = cogl_indices_get_buffer (user_indices);
indices = cogl_buffer_map (COGL_BUFFER (index_buffer), indices = _cogl_buffer_map (COGL_BUFFER (index_buffer),
COGL_BUFFER_ACCESS_READ, 0); COGL_BUFFER_ACCESS_READ, 0,
NULL);
indices_type = cogl_indices_get_type (user_indices); indices_type = cogl_indices_get_type (user_indices);
} }
else else

View File

@ -85,11 +85,19 @@ cogl_indices_new (CoglContext *context,
CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes); CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes);
CoglBuffer *buffer = COGL_BUFFER (index_buffer); CoglBuffer *buffer = COGL_BUFFER (index_buffer);
CoglIndices *indices; CoglIndices *indices;
CoglError *ignore_error = NULL;
cogl_buffer_set_data (buffer, _cogl_buffer_set_data (buffer,
0, 0,
indices_data, indices_data,
buffer_bytes); 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); indices = cogl_indices_new_for_buffer (type, index_buffer, 0);
cogl_object_unref (index_buffer); cogl_object_unref (index_buffer);

View File

@ -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 /* Mapping a buffer for read is probably a really bad thing to
do but this will only happen during debugging so it probably do but this will only happen during debugging so it probably
doesn't matter */ doesn't matter */
verts = ((uint8_t *)cogl_buffer_map (COGL_BUFFER (state->attribute_buffer), verts = ((uint8_t *)_cogl_buffer_map (COGL_BUFFER (state->attribute_buffer),
COGL_BUFFER_ACCESS_READ, 0) + COGL_BUFFER_ACCESS_READ, 0,
NULL) +
state->array_offset); state->array_offset);
_cogl_journal_dump_quad_batch (verts, _cogl_journal_dump_quad_batch (verts,
@ -1065,14 +1066,14 @@ create_attribute_buffer (CoglJournal *journal,
if (vbo == NULL) 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; journal->vbo_pool[journal->next_vbo_in_pool] = vbo;
} }
else if (cogl_buffer_get_size (COGL_BUFFER (vbo)) < n_bytes) else if (cogl_buffer_get_size (COGL_BUFFER (vbo)) < n_bytes)
{ {
/* If the buffer is too small then we'll just recreate it */ /* If the buffer is too small then we'll just recreate it */
cogl_object_unref (vbo); 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; journal->vbo_pool[journal->next_vbo_in_pool] = vbo;
} }
@ -1718,11 +1719,10 @@ _cogl_journal_try_read_pixel (CoglJournal *journal,
CoglBitmap *bitmap, CoglBitmap *bitmap,
CoglBool *found_intersection) CoglBool *found_intersection)
{ {
CoglContext *ctx;
CoglPixelFormat format; CoglPixelFormat format;
int i; int i;
_COGL_GET_CONTEXT (ctx, FALSE);
/* XXX: this number has been plucked out of thin air, but the idea /* 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 * 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 * 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) format != COGL_PIXEL_FORMAT_RGBA_8888)
return FALSE; return FALSE;
ctx = _cogl_bitmap_get_context (bitmap);
*found_intersection = FALSE; *found_intersection = FALSE;
/* NB: The most recently added journal entry is the last entry, and /* 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]; float poly[16];
CoglFramebuffer *framebuffer = journal->framebuffer; CoglFramebuffer *framebuffer = journal->framebuffer;
uint8_t *pixel; uint8_t *pixel;
CoglError *ignore_error;
entry_to_screen_polygon (framebuffer, entry, vertices, poly); entry_to_screen_polygon (framebuffer, entry, vertices, poly);
@ -1799,9 +1802,13 @@ _cogl_journal_try_read_pixel (CoglJournal *journal,
pixel = _cogl_bitmap_map (bitmap, pixel = _cogl_bitmap_map (bitmap,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
&ignore_error);
if (pixel == NULL) if (pixel == NULL)
{
cogl_error_free (ignore_error);
return FALSE; return FALSE;
}
pixel[0] = color[0]; pixel[0] = color[0];
pixel[1] = color[1]; pixel[1] = color[1];

View File

@ -66,10 +66,11 @@ _cogl_pixel_buffer_free (CoglPixelBuffer *buffer);
COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer) COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer)
CoglPixelBuffer * static CoglPixelBuffer *
cogl_pixel_buffer_new (CoglContext *context, _cogl_pixel_buffer_new (CoglContext *context,
size_t size, size_t size,
const void *data) const void *data,
CoglError **error)
{ {
CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer); CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer);
CoglBuffer *buffer = COGL_BUFFER (pixel_buffer); CoglBuffer *buffer = COGL_BUFFER (pixel_buffer);
@ -85,14 +86,34 @@ cogl_pixel_buffer_new (CoglContext *context,
_cogl_pixel_buffer_object_new (pixel_buffer); _cogl_pixel_buffer_object_new (pixel_buffer);
if (data) if (data)
cogl_buffer_set_data (COGL_BUFFER (pixel_buffer), {
if (!_cogl_buffer_set_data (COGL_BUFFER (pixel_buffer),
0, 0,
data, data,
size); size,
error))
{
cogl_object_unref (pixel_buffer);
return NULL;
}
}
return pixel_buffer; 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 static void
_cogl_pixel_buffer_free (CoglPixelBuffer *buffer) _cogl_pixel_buffer_free (CoglPixelBuffer *buffer)
{ {

View File

@ -371,18 +371,20 @@ _cogl_sub_texture_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
return cogl_texture_set_region_from_bitmap (sub_tex->full_texture, return _cogl_texture_set_region_from_bitmap (sub_tex->full_texture,
src_x, src_y, src_x, src_y,
dst_x + sub_tex->sub_x, dst_x + sub_tex->sub_x,
dst_y + sub_tex->sub_y, dst_y + sub_tex->sub_y,
dst_width, dst_height, dst_width, dst_height,
bmp); bmp,
error);
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -55,6 +55,7 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint gl_handle,
CoglTexture2DSliced * CoglTexture2DSliced *
_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat internal_format); CoglPixelFormat internal_format,
CoglError **error);
#endif /* __COGL_TEXTURE_2D_SLICED_PRIVATE_H */ #endif /* __COGL_TEXTURE_2D_SLICED_PRIVATE_H */

View File

@ -162,7 +162,7 @@ _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds,
return waste_buf; return waste_buf;
} }
static void static CoglBool
_cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
CoglTexture2D *slice_tex, CoglTexture2D *slice_tex,
@ -174,7 +174,8 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y) int dst_y,
CoglError **error)
{ {
CoglBool need_x, need_y; CoglBool need_x, need_y;
CoglContext *ctx = COGL_TEXTURE (tex_2ds)->context; CoglContext *ctx = COGL_TEXTURE (tex_2ds)->context;
@ -200,10 +201,9 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
unsigned int wy, wx; unsigned int wy, wx;
CoglBitmap *waste_bmp; 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) if (bmp_data == NULL)
return; return FALSE;
if (need_x) if (need_x)
{ {
@ -234,7 +234,7 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
x_span->waste * bpp, x_span->waste * bpp,
waste_buf); waste_buf);
cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
0, /* src_x */ 0, /* src_x */
0, /* src_y */ 0, /* src_y */
/* dst_x */ /* dst_x */
@ -245,7 +245,13 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
/* dst_height */ /* dst_height */
y_iter->intersect_end - y_iter->intersect_end -
y_iter->intersect_start, y_iter->intersect_start,
waste_bmp); waste_bmp,
error))
{
cogl_object_unref (waste_bmp);
_cogl_bitmap_unmap (source_bmp);
return FALSE;
}
cogl_object_unref (waste_bmp); cogl_object_unref (waste_bmp);
} }
@ -288,7 +294,7 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
copy_width * bpp, copy_width * bpp,
waste_buf); waste_buf);
cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
0, /* src_x */ 0, /* src_x */
0, /* src_y */ 0, /* src_y */
/* dst_x */ /* dst_x */
@ -298,18 +304,27 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
y_span->size - y_span->waste, y_span->size - y_span->waste,
copy_width, /* dst_width */ copy_width, /* dst_width */
y_span->waste, /* dst_height */ y_span->waste, /* dst_height */
waste_bmp); waste_bmp,
error))
{
cogl_object_unref (waste_bmp);
_cogl_bitmap_unmap (source_bmp);
return FALSE;
}
cogl_object_unref (waste_bmp); cogl_object_unref (waste_bmp);
} }
_cogl_bitmap_unmap (source_bmp); _cogl_bitmap_unmap (source_bmp);
} }
return TRUE;
} }
static CoglBool static CoglBool
_cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglSpan *x_span; CoglSpan *x_span;
CoglSpan *y_span; CoglSpan *y_span;
@ -340,7 +355,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
slice_tex = g_array_index (tex_2ds->slice_textures, slice_tex = g_array_index (tex_2ds->slice_textures,
CoglTexture2D *, slice_num); CoglTexture2D *, slice_num);
cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
x_span->start, /* src x */ x_span->start, /* src x */
y_span->start, /* src y */ y_span->start, /* src y */
0, /* dst x */ 0, /* dst x */
@ -349,7 +364,13 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
x_span->waste, /* width */ x_span->waste, /* width */
y_span->size - y_span->size -
y_span->waste, /* height */ y_span->waste, /* height */
bmp); bmp,
error))
{
if (waste_buf)
g_free (waste_buf);
return FALSE;
}
/* Set up a fake iterator that covers the whole slice */ /* Set up a fake iterator that covers the whole slice */
x_iter.intersect_start = x_span->start; x_iter.intersect_start = x_span->start;
@ -364,7 +385,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
y_span->waste); y_span->waste);
y_iter.pos = y_span->start; y_iter.pos = y_span->start;
_cogl_texture_2d_sliced_set_waste (tex_2ds, if (!_cogl_texture_2d_sliced_set_waste (tex_2ds,
bmp, bmp,
slice_tex, slice_tex,
waste_buf, waste_buf,
@ -373,7 +394,13 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
0, /* src_x */ 0, /* src_x */
0, /* src_y */ 0, /* src_y */
0, /* dst_x */ 0, /* dst_x */
0); /* dst_y */ 0,
error)) /* dst_y */
{
if (waste_buf)
g_free (waste_buf);
return FALSE;
}
} }
} }
@ -393,7 +420,8 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
int height, int height,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
CoglSpan *x_span; CoglSpan *x_span;
CoglSpan *y_span; CoglSpan *y_span;
@ -463,26 +491,39 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
slice_tex = g_array_index (tex_2ds->slice_textures, slice_tex = g_array_index (tex_2ds->slice_textures,
CoglTexture2D *, slice_num); CoglTexture2D *, slice_num);
cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
source_x, source_x,
source_y, source_y,
local_x, /* dst x */ local_x, /* dst x */
local_y, /* dst y */ local_y, /* dst y */
inter_w, /* width */ inter_w, /* width */
inter_h, /* height */ inter_h, /* height */
source_bmp); source_bmp,
error))
{
if (waste_buf)
g_free (waste_buf);
return FALSE;
}
_cogl_texture_2d_sliced_set_waste (tex_2ds, if (!_cogl_texture_2d_sliced_set_waste (tex_2ds,
source_bmp, source_bmp,
slice_tex, slice_tex,
waste_buf, waste_buf,
x_span, y_span, x_span, y_span,
&x_iter, &y_iter, &x_iter, &y_iter,
src_x, src_y, src_x, src_y,
dst_x, dst_y); dst_x, dst_y,
error))
{
if (waste_buf)
g_free (waste_buf);
return FALSE;
}
} }
} }
if (waste_buf)
g_free (waste_buf); g_free (waste_buf);
return TRUE; return TRUE;
@ -877,7 +918,8 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
CoglTexture2DSliced * CoglTexture2DSliced *
_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat internal_format) CoglPixelFormat internal_format,
CoglError **error)
{ {
CoglTexture2DSliced *tex_2ds; CoglTexture2DSliced *tex_2ds;
CoglBitmap *dst_bmp; CoglBitmap *dst_bmp;
@ -908,7 +950,8 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
&internal_format, &internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (dst_bmp == NULL) if (dst_bmp == NULL)
{ {
_cogl_texture_2d_sliced_free (tex_2ds); _cogl_texture_2d_sliced_free (tex_2ds);
@ -922,7 +965,8 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
goto error; goto error;
if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds, if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
dst_bmp)) dst_bmp,
error))
goto error; goto error;
cogl_object_unref (dst_bmp); cogl_object_unref (dst_bmp);
@ -1239,33 +1283,40 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
CoglBool status;
bmp = _cogl_texture_prepare_for_upload (bmp, bmp = _cogl_texture_prepare_for_upload (bmp,
cogl_texture_get_format (tex), cogl_texture_get_format (tex),
NULL, NULL,
NULL, NULL,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (!bmp)
return FALSE;
/* Send data to GL */ /* Send data to GL */
status =
_cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds, _cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
bmp, bmp,
gl_format, gl_format,
gl_type); gl_type,
error);
cogl_object_unref (bmp); cogl_object_unref (bmp);
return TRUE; return status;
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -481,21 +481,26 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int width, int width,
unsigned int height, int height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglContext *ctx = tex->context; CoglContext *ctx = tex->context;
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, if (!ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d,
bmp, bmp,
dst_x, dst_x,
dst_y, dst_y,
src_x, src_x,
src_y, src_y,
width, width,
height); height,
error))
{
return FALSE;
}
tex_2d->mipmaps_dirty = TRUE; tex_2d->mipmaps_dirty = TRUE;

View File

@ -271,7 +271,6 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
uint8_t *data;
CoglContext *ctx; CoglContext *ctx;
ctx = _cogl_bitmap_get_context (bmp); ctx = _cogl_bitmap_get_context (bmp);
@ -293,14 +292,10 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
&internal_format, &internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (dst_bmp == NULL) 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, tex_3d = _cogl_texture_3d_create_base (ctx,
bmp_width, height, depth, bmp_width, height, depth,
@ -308,23 +303,38 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
/* Keep a copy of the first pixel so that if glGenerateMipmap isn't /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */ supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
(data = _cogl_bitmap_map (dst_bmp,
COGL_BUFFER_ACCESS_READ, 0)))
{ {
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); CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
tex_3d->first_pixel.gl_format = gl_format; tex_3d->first_pixel.gl_format = gl_format;
tex_3d->first_pixel.gl_type = gl_type; tex_3d->first_pixel.gl_type = gl_type;
if (data)
{
memcpy (tex_3d->first_pixel.data, data, memcpy (tex_3d->first_pixel.data, data,
_cogl_pixel_format_get_bytes_per_pixel (format)); _cogl_pixel_format_get_bytes_per_pixel (format));
_cogl_bitmap_unmap (dst_bmp); _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 = tex_3d->gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format); ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
ctx->texture_driver->upload_to_gl_3d (ctx, if (!ctx->texture_driver->upload_to_gl_3d (ctx,
GL_TEXTURE_3D, GL_TEXTURE_3D,
tex_3d->gl_texture, tex_3d->gl_texture,
FALSE, /* is_foreign */ FALSE, /* is_foreign */
@ -333,7 +343,13 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
dst_bmp, dst_bmp,
gl_intformat, gl_intformat,
gl_format, gl_format,
gl_type); gl_type,
error))
{
cogl_object_unref (dst_bmp);
cogl_object_unref (tex_3d);
return NULL;
}
tex_3d->gl_format = gl_intformat; tex_3d->gl_format = gl_intformat;
@ -393,7 +409,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
bmp_data = _cogl_bitmap_map (bitmap, bmp_data = _cogl_bitmap_map (bitmap,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD); COGL_BUFFER_MAP_HINT_DISCARD,
error);
if (bmp_data == NULL) if (bmp_data == NULL)
{ {
@ -574,12 +591,19 @@ _cogl_texture_3d_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
/* This function doesn't really make sense for 3D textures because /* This function doesn't really make sense for 3D textures because
it can't specify which image to upload to */ 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; return FALSE;
} }

View File

@ -63,7 +63,7 @@ struct _CoglTextureDriver
* *
* XXX: sorry for the ridiculous number of arguments :-( * XXX: sorry for the ridiculous number of arguments :-(
*/ */
void CoglBool
(* upload_subregion_to_gl) (CoglContext *ctx, (* upload_subregion_to_gl) (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -76,7 +76,8 @@ struct _CoglTextureDriver
int height, int height,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLuint source_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. On * 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 * to copy the bitmap if the rowstride is not a multiple of a possible
* alignment value because there is no GL_UNPACK_ROW_LENGTH * alignment value because there is no GL_UNPACK_ROW_LENGTH
*/ */
void CoglBool
(* upload_to_gl) (CoglContext *ctx, (* upload_to_gl) (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -92,7 +93,8 @@ struct _CoglTextureDriver
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_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 * 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 * is the number of rows between images) is inferred by dividing the
* height of the bitmap by the depth. * height of the bitmap by the depth.
*/ */
void CoglBool
(* upload_to_gl_3d) (CoglContext *ctx, (* upload_to_gl_3d) (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -111,7 +113,8 @@ struct _CoglTextureDriver
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_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 * This sets up the glPixelStore state for an download to a destination with

View File

@ -70,9 +70,10 @@ struct _CoglTextureVtable
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bitmap); CoglBitmap *bitmap,
CoglError **error);
/* This should copy the image data of the texture into @data. The /* This should copy the image data of the texture into @data. The
requested format will have been first passed through requested format will have been first passed through
@ -233,17 +234,19 @@ _cogl_texture_determine_internal_format (CoglPixelFormat src_format,
CoglPixelFormat dst_format); CoglPixelFormat dst_format);
/* Utility function to help uploading a bitmap. If the bitmap needs /* Utility function to help uploading a bitmap. If the bitmap needs
premult conversion then it will be copied and *copied_bitmap will * premult conversion then a converted copy will be returned,
be set to TRUE. Otherwise dst_bmp will be set to a shallow copy of * otherwise a reference to the original source will be returned.
src_bmp. The GLenums needed for uploading are returned */ *
* The GLenums needed for uploading are returned
*/
CoglBitmap * CoglBitmap *
_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp, _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
CoglPixelFormat dst_format, CoglPixelFormat dst_format,
CoglPixelFormat *dst_format_out, CoglPixelFormat *dst_format_out,
GLenum *out_glintformat, GLenum *out_glintformat,
GLenum *out_glformat, GLenum *out_glformat,
GLenum *out_gltype); GLenum *out_gltype,
CoglError **error);
void void
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); _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 width,
int rowstride); 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 CoglBool
_cogl_texture_is_foreign (CoglTexture *texture); _cogl_texture_is_foreign (CoglTexture *texture);
@ -301,4 +295,21 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
CoglTextureType CoglTextureType
_cogl_texture_get_type (CoglTexture *texture); _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 */ #endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -38,6 +38,7 @@
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
#include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-opengl-private.h"
#include "cogl-error-private.h" #include "cogl-error-private.h"
#include "cogl-util-gl-private.h"
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
@ -185,7 +186,7 @@ _cogl_texture_rectangle_create_base (CoglContext *ctx,
tex_rect->format = internal_format; tex_rect->format = internal_format;
return tex_rect; return _cogl_texture_rectangle_object_new (tex_rect);
} }
CoglTextureRectangle * CoglTextureRectangle *
@ -199,6 +200,7 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
GLenum gl_error;
/* Since no data, we need some internal format */ /* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY) 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, _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
tex_rect->gl_texture, tex_rect->gl_texture,
tex_rect->is_foreign); 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 * CoglTextureRectangle *
@ -264,7 +277,8 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
&internal_format, &internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (dst_bmp == NULL) if (dst_bmp == NULL)
return NULL; return NULL;
@ -278,20 +292,26 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
ctx->texture_driver->gen (ctx, ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
internal_format); internal_format);
ctx->texture_driver->upload_to_gl (ctx, if (!ctx->texture_driver->upload_to_gl (ctx,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
tex_rect->gl_texture, tex_rect->gl_texture,
FALSE, FALSE,
dst_bmp, dst_bmp,
gl_intformat, gl_intformat,
gl_format, gl_format,
gl_type); gl_type,
error))
{
cogl_object_unref (dst_bmp);
cogl_object_unref (tex_rect);
return NULL;
}
tex_rect->gl_format = gl_intformat; tex_rect->gl_format = gl_intformat;
cogl_object_unref (dst_bmp); cogl_object_unref (dst_bmp);
return _cogl_texture_rectangle_object_new (tex_rect); return tex_rect;
} }
CoglTextureRectangle * 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_min_filter = GL_FALSE;
tex_rect->gl_legacy_texobj_mag_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 static int
@ -532,23 +552,29 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
CoglContext *ctx = tex->context; CoglContext *ctx = tex->context;
CoglBool status;
bmp = _cogl_texture_prepare_for_upload (bmp, bmp = _cogl_texture_prepare_for_upload (bmp,
cogl_texture_get_format (tex), cogl_texture_get_format (tex),
NULL, NULL,
NULL, NULL,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (!bmp)
return FALSE;
/* Send data to GL */ /* Send data to GL */
status =
ctx->texture_driver->upload_subregion_to_gl (ctx, ctx->texture_driver->upload_subregion_to_gl (ctx,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
tex_rect->gl_texture, tex_rect->gl_texture,
@ -558,11 +584,12 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
dst_width, dst_height, dst_width, dst_height,
bmp, bmp,
gl_format, gl_format,
gl_type); gl_type,
error);
cogl_object_unref (bmp); cogl_object_unref (bmp);
return TRUE; return status;
} }
static CoglBool static CoglBool

View File

@ -55,6 +55,7 @@
#include "cogl1-context.h" #include "cogl1-context.h"
#include "cogl-sub-texture.h" #include "cogl-sub-texture.h"
#include "cogl-primitive-texture.h" #include "cogl-primitive-texture.h"
#include "cogl-error-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -188,13 +189,13 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
CoglPixelFormat *dst_format_out, CoglPixelFormat *dst_format_out,
GLenum *out_glintformat, GLenum *out_glintformat,
GLenum *out_glformat, GLenum *out_glformat,
GLenum *out_gltype) GLenum *out_gltype,
CoglError **error)
{ {
CoglContext *ctx = _cogl_bitmap_get_context (src_bmp);
CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp); CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
CoglBitmap *dst_bmp; CoglBitmap *dst_bmp;
_COGL_GET_CONTEXT (ctx, NULL);
dst_format = _cogl_texture_determine_internal_format (src_format, dst_format = _cogl_texture_determine_internal_format (src_format,
dst_format); dst_format);
@ -222,7 +223,8 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
dst_format)) dst_format))
{ {
dst_bmp = _cogl_bitmap_convert (src_bmp, dst_bmp = _cogl_bitmap_convert (src_bmp,
src_format ^ COGL_PREMULT_BIT); src_format ^ COGL_PREMULT_BIT,
error);
if (dst_bmp == NULL) if (dst_bmp == NULL)
return NULL; return NULL;
@ -256,7 +258,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
out_gltype); out_gltype);
if (closest_format != src_format) 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 else
dst_bmp = cogl_object_ref (src_bmp); dst_bmp = cogl_object_ref (src_bmp);
} }
@ -354,25 +356,22 @@ cogl_texture_new_with_size (unsigned int width,
return tex; return tex;
} }
CoglTexture * static CoglTexture *
cogl_texture_new_from_data (unsigned int width, _cogl_texture_new_from_data (CoglContext *ctx,
unsigned int height, int width,
int height,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat format, CoglPixelFormat format,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
unsigned int rowstride, int rowstride,
const uint8_t *data) const uint8_t *data,
CoglError **error)
{ {
CoglBitmap *bmp; CoglBitmap *bmp;
CoglTexture *tex; CoglTexture *tex;
_COGL_GET_CONTEXT (ctx, NULL); _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
_COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL);
if (format == COGL_PIXEL_FORMAT_ANY)
return NULL;
if (data == NULL)
return NULL;
/* Rowstride from width if not given */ /* Rowstride from width if not given */
if (rowstride == 0) if (rowstride == 0)
@ -385,7 +384,7 @@ cogl_texture_new_from_data (unsigned int width,
rowstride, rowstride,
(uint8_t *) data); (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); cogl_object_unref (bmp);
@ -393,21 +392,60 @@ cogl_texture_new_from_data (unsigned int width,
} }
CoglTexture * CoglTexture *
cogl_texture_new_from_bitmap (CoglBitmap *bitmap, cogl_texture_new_from_data (int width,
int height,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat internal_format) CoglPixelFormat format,
CoglPixelFormat internal_format,
int rowstride,
const uint8_t *data)
{ {
CoglAtlasTexture *atlas_tex; CoglError *ignore_error = NULL;
CoglTexture *tex; 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 */ /* First try putting the texture in the atlas */
if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap, if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap,
flags, flags,
internal_format))) internal_format,
&internal_error)))
return COGL_TEXTURE (atlas_tex); 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 that doesn't work try a fast path 2D texture */
if ((_cogl_util_is_pot (bitmap->width) && if ((_cogl_util_is_pot (bitmap->width) &&
_cogl_util_is_pot (bitmap->height)) || _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, tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap,
internal_format, 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 else
tex = NULL; tex = NULL;
@ -432,12 +484,27 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
/* Otherwise create a sliced texture */ /* Otherwise create a sliced texture */
tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap, tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap,
flags, flags,
internal_format)); internal_format,
error));
} }
return tex; 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 * CoglTexture *
cogl_texture_new_from_file (const char *filename, cogl_texture_new_from_file (const char *filename,
CoglTextureFlags flags, CoglTextureFlags flags,
@ -465,8 +532,13 @@ cogl_texture_new_from_file (const char *filename,
internal_format = internal_format =
_cogl_texture_determine_internal_format (src_format, internal_format); _cogl_texture_determine_internal_format (src_format, internal_format);
if (!_cogl_texture_needs_premult_conversion (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)) _cogl_bitmap_convert_premult_status (bmp,
texture = cogl_texture_new_from_bitmap (bmp, flags, internal_format); src_format ^ COGL_PREMULT_BIT,
error))
{
texture =
_cogl_texture_new_from_bitmap (bmp, flags, internal_format, error);
}
cogl_object_unref (bmp); cogl_object_unref (bmp);
@ -664,14 +736,15 @@ _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture)
} }
CoglBool CoglBool
cogl_texture_set_region_from_bitmap (CoglTexture *texture, _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, unsigned int dst_width,
unsigned int dst_height, unsigned int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
CoglBool ret; CoglBool ret;
@ -695,13 +768,38 @@ cogl_texture_set_region_from_bitmap (CoglTexture *texture,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
bmp); bmp,
error);
return ret; return ret;
} }
CoglBool CoglBool
cogl_texture_set_region (CoglTexture *texture, 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_x,
int src_y, int src_y,
int dst_x, int dst_x,
@ -712,7 +810,8 @@ cogl_texture_set_region (CoglTexture *texture,
int height, int height,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,
const uint8_t *data) const uint8_t *data,
CoglError **error)
{ {
CoglContext *ctx = texture->context; CoglContext *ctx = texture->context;
CoglBitmap *source_bmp; CoglBitmap *source_bmp;
@ -736,17 +835,47 @@ cogl_texture_set_region (CoglTexture *texture,
rowstride, rowstride,
(uint8_t *) data); (uint8_t *) data);
ret = cogl_texture_set_region_from_bitmap (texture, ret = _cogl_texture_set_region_from_bitmap (texture,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
source_bmp); source_bmp,
error);
cogl_object_unref (source_bmp); cogl_object_unref (source_bmp);
return ret; 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 /* Reads back the contents of a texture by rendering it to the framebuffer
* and reading back the resulting pixels. * 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 * NB: Normally this approach isn't normally used since we can just use
* glGetTexImage, but may be used as a fallback in some circumstances. * glGetTexImage, but may be used as a fallback in some circumstances.
*/ */
static void static CoglBool
do_texture_draw_and_read (CoglFramebuffer *fb, do_texture_draw_and_read (CoglFramebuffer *fb,
CoglPipeline *pipeline, CoglPipeline *pipeline,
CoglTexture *texture, CoglTexture *texture,
CoglBitmap *target_bmp, CoglBitmap *target_bmp,
float *viewport) float *viewport,
CoglError **error)
{ {
float rx1, ry1; float rx1, ry1;
float rx2, ry2; float rx2, ry2;
@ -828,24 +958,36 @@ do_texture_draw_and_read (CoglFramebuffer *fb,
width, height, width, height,
COGL_PIXEL_FORMAT_RGBA_8888_PRE); COGL_PIXEL_FORMAT_RGBA_8888_PRE);
cogl_framebuffer_read_pixels_into_bitmap if (!_cogl_framebuffer_read_pixels_into_bitmap
(fb, (fb,
viewport[0], viewport[1], viewport[0], viewport[1],
COGL_READ_PIXELS_COLOR_BUFFER, COGL_READ_PIXELS_COLOR_BUFFER,
rect_bmp); rect_bmp,
error))
{
cogl_object_unref (rect_bmp);
return FALSE;
}
/* Copy to target bitmap */ /* Copy to target bitmap */
_cogl_bitmap_copy_subregion (rect_bmp, if (!_cogl_bitmap_copy_subregion (rect_bmp,
target_bmp, target_bmp,
0,0, 0, 0,
rx1,ry1, rx1, ry1,
width, width,
height); height,
error))
{
cogl_object_unref (rect_bmp);
return FALSE;
}
/* Free temp bitmap */ /* Free temp bitmap */
cogl_object_unref (rect_bmp); cogl_object_unref (rect_bmp);
} }
} }
return TRUE;
} }
/* Reads back the contents of a texture by rendering it to the framebuffer /* 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 * NB: Normally this approach isn't normally used since we can just use
* glGetTexImage, but may be used as a fallback in some circumstances. * glGetTexImage, but may be used as a fallback in some circumstances.
*/ */
CoglBool static CoglBool
_cogl_texture_draw_and_read (CoglTexture *texture, _cogl_texture_draw_and_read (CoglTexture *texture,
CoglBitmap *target_bmp, CoglBitmap *target_bmp,
GLuint target_gl_format, GLuint target_gl_format,
GLuint target_gl_type) GLuint target_gl_type,
CoglError **error)
{ {
int bpp;
CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer (); 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; 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[0] = 0;
viewport[1] = 0;
/* Viewport needs to have some size and be inside the window for this */ viewport[2] = cogl_framebuffer_get_width (framebuffer);
cogl_framebuffer_get_viewport4fv (framebuffer, viewport); viewport[3] = cogl_framebuffer_get_height (framebuffer);
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)
*/
cogl_framebuffer_get_viewport4fv (framebuffer, save_viewport);
_cogl_framebuffer_push_projection (framebuffer); _cogl_framebuffer_push_projection (framebuffer);
cogl_framebuffer_orthographic (framebuffer, cogl_framebuffer_orthographic (framebuffer,
0, 0, 0, 0,
viewport[2], viewport[3], viewport[2],
viewport[3],
0, 100); 0, 100);
cogl_framebuffer_push_matrix (framebuffer); cogl_framebuffer_push_matrix (framebuffer);
@ -912,36 +1046,38 @@ _cogl_texture_draw_and_read (CoglTexture *texture,
COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST); COGL_PIPELINE_FILTER_NEAREST);
do_texture_draw_and_read (framebuffer, if (!do_texture_draw_and_read (framebuffer,
ctx->texture_download_pipeline, ctx->texture_download_pipeline,
texture, target_bmp, viewport); texture, target_bmp, viewport,
error))
return FALSE;
/* Check whether texture has alpha and framebuffer not */ /* XXX: As an alleged PowerVR driver bug workaround where the driver
/* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer * is apparently not maintaining the alpha component of some
still doesn't seem to have an alpha buffer. This might be just * framebuffers we render the alpha component of the texture
a PowerVR issue. * separately to be sure we retrieve all components of the texture.
GLint r_bits, g_bits, b_bits, a_bits; *
GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); * TODO: verify if this is still an issue
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); */
if ((cogl_texture_get_format (texture) & COGL_A_BIT)/* && a_bits == 0*/) if ((cogl_texture_get_format (texture) & COGL_A_BIT)/* && a_bits == 0*/)
{ {
uint8_t *srcdata; uint8_t *srcdata;
uint8_t *dstdata; uint8_t *dstdata;
uint8_t *srcpixel; uint8_t *srcpixel;
uint8_t *dstpixel; 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; int alpha_rowstride = bpp * target_width;
CoglBitmap *alpha_bmp;
int x,y;
if ((dstdata = _cogl_bitmap_map (target_bmp, if ((dstdata = _cogl_bitmap_map (target_bmp,
COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD)) == NULL) COGL_BUFFER_MAP_HINT_DISCARD,
return FALSE; error)) == NULL)
goto EXIT;
/* Create temp bitmap for alpha values */ /* Create temp bitmap for alpha values */
alpha_bmp = alpha_bmp =
@ -956,15 +1092,24 @@ _cogl_texture_draw_and_read (CoglTexture *texture,
"RGBA = REPLACE (TEXTURE[A])", "RGBA = REPLACE (TEXTURE[A])",
NULL); NULL);
do_texture_draw_and_read (framebuffer, if (!do_texture_draw_and_read (framebuffer,
ctx->texture_download_pipeline, ctx->texture_download_pipeline,
texture, alpha_bmp, viewport); texture, alpha_bmp, viewport,
error))
{
cogl_object_unref (alpha_bmp);
_cogl_bitmap_unmap (target_bmp);
goto EXIT;
}
/* Copy temp R to target A */ /* 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, srcdata = _cogl_bitmap_map (alpha_bmp,
COGL_BUFFER_ACCESS_READ, COGL_BUFFER_ACCESS_READ,
0 /* hints */); 0 /* hints */,
NULL);
for (y=0; y<target_height; ++y) for (y=0; y<target_height; ++y)
{ {
@ -985,11 +1130,19 @@ _cogl_texture_draw_and_read (CoglTexture *texture,
cogl_object_unref (alpha_bmp); cogl_object_unref (alpha_bmp);
} }
status = TRUE;
EXIT:
/* Restore old state */ /* Restore old state */
cogl_framebuffer_pop_matrix (framebuffer); cogl_framebuffer_pop_matrix (framebuffer);
_cogl_framebuffer_pop_projection (framebuffer); _cogl_framebuffer_pop_projection (framebuffer);
cogl_framebuffer_set_viewport (framebuffer,
save_viewport[0],
save_viewport[1],
save_viewport[2],
save_viewport[3]);
return TRUE; return status;
} }
static CoglBool static CoglBool
@ -1007,6 +1160,7 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
CoglFramebuffer *framebuffer; CoglFramebuffer *framebuffer;
CoglBitmap *bitmap; CoglBitmap *bitmap;
CoglBool ret; CoglBool ret;
CoglError *ignore_error = NULL;
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
return FALSE; return FALSE;
@ -1026,10 +1180,15 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
dst_format, dst_format,
dst_rowstride, dst_rowstride,
dst_bits); dst_bits);
ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer, ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
x, y, x, y,
COGL_READ_PIXELS_COLOR_BUFFER, COGL_READ_PIXELS_COLOR_BUFFER,
bitmap); bitmap,
&ignore_error);
if (!ret)
cogl_error_free (ignore_error);
cogl_object_unref (bitmap); cogl_object_unref (bitmap);
cogl_object_unref (framebuffer); cogl_object_unref (framebuffer);
@ -1092,6 +1251,7 @@ typedef struct
CoglBitmap *target_bmp; CoglBitmap *target_bmp;
uint8_t *target_bits; uint8_t *target_bits;
CoglBool success; CoglBool success;
CoglError *error;
} CoglTextureGetData; } CoglTextureGetData;
static void static void
@ -1176,6 +1336,7 @@ cogl_texture_get_data (CoglTexture *texture,
int tex_width; int tex_width;
int tex_height; int tex_height;
CoglPixelFormat texture_format; CoglPixelFormat texture_format;
CoglError *ignore_error = NULL;
CoglTextureGetData tg_data; CoglTextureGetData tg_data;
@ -1252,16 +1413,15 @@ cogl_texture_get_data (CoglTexture *texture,
tex_width, tex_height, tex_width, tex_height,
closest_format); closest_format);
tg_data.target_bits = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE,
COGL_BUFFER_MAP_HINT_DISCARD,
&ignore_error);
if (tg_data.target_bits)
{
tg_data.orig_width = tex_width; tg_data.orig_width = tex_width;
tg_data.orig_height = tex_height; tg_data.orig_height = tex_height;
tg_data.target_bmp = target_bmp; tg_data.target_bmp = target_bmp;
tg_data.target_bits = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE, tg_data.error = NULL;
COGL_BUFFER_MAP_HINT_DISCARD);
if (tg_data.target_bits == NULL)
{
cogl_object_unref (target_bmp);
return 0;
}
tg_data.success = TRUE; tg_data.success = TRUE;
/* If there are any dependent framebuffers on the texture then we /* If there are any dependent framebuffers on the texture then we
@ -1281,21 +1441,40 @@ cogl_texture_get_data (CoglTexture *texture,
&tg_data); &tg_data);
_cogl_bitmap_unmap (target_bmp); _cogl_bitmap_unmap (target_bmp);
}
else
{
cogl_error_free (ignore_error);
tg_data.success = FALSE;
}
/* XXX: In some cases _cogl_texture_2d_download_from_gl may fail /* XXX: In some cases _cogl_texture_2d_download_from_gl may fail
* to read back the texture data; such as for GLES which doesn't * to read back the texture data; such as for GLES which doesn't
* support glGetTexImage, so here we fallback to drawing the * support glGetTexImage, so here we fallback to drawing the
* texture and reading the pixels from the framebuffer. */ * texture and reading the pixels from the framebuffer. */
if (!tg_data.success) if (!tg_data.success)
_cogl_texture_draw_and_read (texture, target_bmp, {
if (!_cogl_texture_draw_and_read (texture, target_bmp,
closest_gl_format, closest_gl_format,
closest_gl_type); closest_gl_type,
&ignore_error))
{
/* We have no more fallbacks so we just give up and
* hope for the best */
g_warning ("Failed to read texture since draw-and-read "
"fallback failed: %s", ignore_error->message);
cogl_error_free (ignore_error);
cogl_object_unref (target_bmp);
return 0;
}
}
/* Was intermediate used? */ /* Was intermediate used? */
if (closest_format != format) if (closest_format != format)
{ {
CoglBitmap *new_bmp; CoglBitmap *new_bmp;
CoglBool result; CoglBool result;
CoglError *error = NULL;
/* Convert to requested format directly into the user's buffer */ /* Convert to requested format directly into the user's buffer */
new_bmp = cogl_bitmap_new_for_data (ctx, new_bmp = cogl_bitmap_new_for_data (ctx,
@ -1303,11 +1482,14 @@ cogl_texture_get_data (CoglTexture *texture,
format, format,
rowstride, rowstride,
data); data);
result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp); result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp, &error);
if (!result) if (!result)
{
cogl_error_free (error);
/* Return failure after cleaning up */ /* Return failure after cleaning up */
byte_size = 0; byte_size = 0;
}
cogl_object_unref (new_bmp); cogl_object_unref (new_bmp);
} }

View File

@ -173,12 +173,12 @@ cogl_texture_new_from_file (const char *filename,
* Since: 0.8 * Since: 0.8
*/ */
CoglTexture * CoglTexture *
cogl_texture_new_from_data (unsigned int width, cogl_texture_new_from_data (int width,
unsigned int height, int height,
CoglTextureFlags flags, CoglTextureFlags flags,
CoglPixelFormat format, CoglPixelFormat format,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
unsigned int rowstride, int rowstride,
const uint8_t *data); const uint8_t *data);
/** /**

View File

@ -912,7 +912,6 @@ _cogl_system_error_domain
_cogl_texture_associate_framebuffer _cogl_texture_associate_framebuffer
_cogl_texture_can_hardware_repeat _cogl_texture_can_hardware_repeat
_cogl_texture_determine_internal_format _cogl_texture_determine_internal_format
_cogl_texture_draw_and_read
_cogl_texture_ensure_non_quad_rendering _cogl_texture_ensure_non_quad_rendering
_cogl_texture_flush_journal_rendering _cogl_texture_flush_journal_rendering
_cogl_texture_free _cogl_texture_free

View File

@ -1426,9 +1426,9 @@ _cogl_path_build_stroke_attribute_buffer (CoglPath *path)
return; return;
data->stroke_attribute_buffer = data->stroke_attribute_buffer =
cogl_attribute_buffer_new (data->context, cogl_attribute_buffer_new_with_size (data->context,
data->path_nodes->len * sizeof (floatVec2), data->path_nodes->len *
NULL); sizeof (floatVec2));
buffer = COGL_BUFFER (data->stroke_attribute_buffer); buffer = COGL_BUFFER (data->stroke_attribute_buffer);
buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer); buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer);

View File

@ -467,8 +467,16 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
{ {
attribute_buffer = cogl_attribute_get_buffer (attribute); attribute_buffer = cogl_attribute_get_buffer (attribute);
buffer = COGL_BUFFER (attribute_buffer); 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) if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL)
setup_generic_buffered_attribute (ctx, pipeline, attribute, base); setup_generic_buffered_attribute (ctx, pipeline, attribute, base);

View File

@ -44,7 +44,8 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints); CoglBufferMapHint hints,
CoglError **error);
void void
_cogl_buffer_gl_unmap (CoglBuffer *buffer); _cogl_buffer_gl_unmap (CoglBuffer *buffer);
@ -53,10 +54,13 @@ CoglBool
_cogl_buffer_gl_set_data (CoglBuffer *buffer, _cogl_buffer_gl_set_data (CoglBuffer *buffer,
unsigned int offset, unsigned int offset,
const void *data, const void *data,
unsigned int size); unsigned int size,
CoglError **error);
void * void *
_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target); _cogl_buffer_gl_bind (CoglBuffer *buffer,
CoglBufferBindTarget target,
CoglError **error);
void void
_cogl_buffer_gl_unbind (CoglBuffer *buffer); _cogl_buffer_gl_unbind (CoglBuffer *buffer);

View File

@ -31,6 +31,8 @@
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-buffer-gl-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: * GL/GLES compatibility defines for the buffer API:
@ -126,22 +128,34 @@ convert_bind_target_to_gl_target (CoglBufferBindTarget target)
} }
} }
static void static CoglBool
recreate_store (CoglBuffer *buffer) recreate_store (CoglBuffer *buffer,
CoglError **error)
{ {
CoglContext *ctx = buffer->context;
GLenum gl_target; GLenum gl_target;
GLenum gl_enum; GLenum gl_enum;
GLenum gl_error;
/* This assumes the buffer is already bound */ /* This assumes the buffer is already bound */
gl_target = convert_bind_target_to_gl_target (buffer->last_target); gl_target = convert_bind_target_to_gl_target (buffer->last_target);
gl_enum = update_hints_to_gl_enum (buffer); gl_enum = update_hints_to_gl_enum (buffer);
GE( buffer->context, glBufferData (gl_target, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glBufferData (gl_target,
buffer->size, buffer->size,
NULL, NULL,
gl_enum) ); gl_enum);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
return FALSE;
buffer->store_created = TRUE; buffer->store_created = TRUE;
return TRUE;
} }
GLenum GLenum
@ -188,19 +202,26 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
size_t offset, size_t offset,
size_t size, size_t size,
CoglBufferAccess access, CoglBufferAccess access,
CoglBufferMapHint hints) CoglBufferMapHint hints,
CoglError **error)
{ {
uint8_t *data; uint8_t *data;
CoglBufferBindTarget target; CoglBufferBindTarget target;
GLenum gl_target; GLenum gl_target;
CoglContext *ctx = buffer->context; CoglContext *ctx = buffer->context;
GLenum gl_error;
if ((access & COGL_BUFFER_ACCESS_READ) && if (((access & COGL_BUFFER_ACCESS_READ) &&
!cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) ||
return NULL; ((access & COGL_BUFFER_ACCESS_WRITE) &&
if ((access & COGL_BUFFER_ACCESS_WRITE) && !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_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; return NULL;
}
target = buffer->last_target; target = buffer->last_target;
_cogl_buffer_bind_no_create (buffer, 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; gl_access |= GL_MAP_INVALIDATE_RANGE_BIT;
if (!buffer->store_created) if (!buffer->store_created)
recreate_store (buffer); {
if (!recreate_store (buffer, error))
{
_cogl_buffer_gl_unbind (buffer);
return NULL;
}
}
GE_RET( data, /* Clear any GL errors */
ctx, while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
glMapBufferRange (gl_target, ;
data = ctx->glMapBufferRange (gl_target,
offset, offset,
size, size,
gl_access) ); 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 else
{ {
@ -244,14 +281,29 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
(hints & COGL_BUFFER_MAP_HINT_DISCARD) || (hints & COGL_BUFFER_MAP_HINT_DISCARD) ||
((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
offset == 0 && size >= buffer->size)) offset == 0 && size >= buffer->size))
recreate_store (buffer); {
if (!recreate_store (buffer, error))
{
_cogl_buffer_gl_unbind (buffer);
return NULL;
}
}
GE_RET( data, /* Clear any GL errors */
ctx, while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
glMapBuffer (gl_target, ;
_cogl_buffer_access_to_gl_enum (access)) );
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);
if (data)
data += offset; data += offset;
} }
@ -281,26 +333,50 @@ CoglBool
_cogl_buffer_gl_set_data (CoglBuffer *buffer, _cogl_buffer_gl_set_data (CoglBuffer *buffer,
unsigned int offset, unsigned int offset,
const void *data, const void *data,
unsigned int size) unsigned int size,
CoglError **error)
{ {
CoglBufferBindTarget target; CoglBufferBindTarget target;
GLenum gl_target; GLenum gl_target;
CoglContext *ctx = buffer->context; CoglContext *ctx = buffer->context;
GLenum gl_error;
CoglBool status = TRUE;
CoglError *internal_error = NULL;
target = buffer->last_target; 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); 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); _cogl_buffer_gl_unbind (buffer);
return TRUE; return status;
} }
void * void *
_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target) _cogl_buffer_gl_bind (CoglBuffer *buffer,
CoglBufferBindTarget target,
CoglError **error)
{ {
void *ret; void *ret;
@ -311,7 +387,13 @@ _cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target)
* store is created. */ * store is created. */
if ((buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) && if ((buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) &&
!buffer->store_created) !buffer->store_created)
recreate_store (buffer); {
if (!recreate_store (buffer, error))
{
_cogl_buffer_gl_unbind (buffer);
return NULL;
}
}
return ret; return ret;
} }

View File

@ -1067,7 +1067,14 @@ _cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer,
attributes, n_attributes); attributes, n_attributes);
buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); 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); buffer_offset = cogl_indices_get_offset (indices);
index_size = sizeof_index_type (cogl_indices_get_type (indices)); index_size = sizeof_index_type (cogl_indices_get_type (indices));

View File

@ -93,7 +93,7 @@ _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d);
void void
_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d);
void CoglBool
_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
CoglBitmap *bitmap, CoglBitmap *bitmap,
int dst_x, int dst_x,
@ -101,7 +101,8 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
int src_x, int src_x,
int src_y, int src_y,
int width, int width,
int height); int height,
CoglError **error);
void void
_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,

View File

@ -143,20 +143,16 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
uint8_t *data;
if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp, dst_bmp = _cogl_texture_prepare_for_upload (bmp,
internal_format, internal_format,
&internal_format, &internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type)) == NULL) &gl_type,
{ error);
_cogl_set_error (error, COGL_TEXTURE_ERROR, if (!dst_bmp)
COGL_TEXTURE_ERROR_FORMAT,
"Failed to prepare texture upload due to format");
return NULL; return NULL;
}
tex_2d = _cogl_texture_2d_create_base (ctx, tex_2d = _cogl_texture_2d_create_base (ctx,
cogl_bitmap_get_width (bmp), 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 /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */ supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
(data = _cogl_bitmap_map (dst_bmp,
COGL_BUFFER_ACCESS_READ, 0)))
{ {
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); CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
tex_2d->first_pixel.gl_format = gl_format; tex_2d->first_pixel.gl_format = gl_format;
tex_2d->first_pixel.gl_type = gl_type; tex_2d->first_pixel.gl_type = gl_type;
if (data)
{
memcpy (tex_2d->first_pixel.data, data, memcpy (tex_2d->first_pixel.data, data,
_cogl_pixel_format_get_bytes_per_pixel (format)); _cogl_pixel_format_get_bytes_per_pixel (format));
_cogl_bitmap_unmap (dst_bmp); _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 = tex_2d->gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
ctx->texture_driver->upload_to_gl (ctx, if (!ctx->texture_driver->upload_to_gl (ctx,
GL_TEXTURE_2D, GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE, FALSE,
dst_bmp, dst_bmp,
gl_intformat, gl_intformat,
gl_format, gl_format,
gl_type); gl_type,
error))
{
cogl_object_unref (dst_bmp);
cogl_object_unref (tex_2d);
return NULL;
}
tex_2d->gl_format = gl_intformat; tex_2d->gl_format = gl_intformat;
@ -502,7 +518,7 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d)
#endif #endif
} }
void CoglBool
_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
CoglBitmap *bmp, CoglBitmap *bmp,
int dst_x, int dst_x,
@ -510,39 +526,56 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
int src_x, int src_x,
int src_y, int src_y,
int width, int width,
int height) int height,
CoglError **error)
{ {
CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglContext *ctx = tex->context; CoglContext *ctx = tex->context;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
uint8_t *data; CoglBool status = TRUE;
bmp = _cogl_texture_prepare_for_upload (bmp, bmp = _cogl_texture_prepare_for_upload (bmp,
cogl_texture_get_format (tex), cogl_texture_get_format (tex),
NULL, NULL,
NULL, NULL,
&gl_format, &gl_format,
&gl_type); &gl_type,
error);
if (!bmp)
return FALSE;
/* If this touches the first pixel then we'll update our copy */ /* If this touches the first pixel then we'll update our copy */
if (dst_x == 0 && dst_y == 0 && if (dst_x == 0 && dst_y == 0 &&
!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
(data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
{ {
CoglError *ignore = NULL;
uint8_t *data =
_cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore);
CoglPixelFormat bpp = CoglPixelFormat bpp =
_cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp)); _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_format = gl_format;
tex_2d->first_pixel.gl_type = gl_type; tex_2d->first_pixel.gl_type = gl_type;
if (data)
{
memcpy (tex_2d->first_pixel.data, memcpy (tex_2d->first_pixel.data,
data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x, data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
bpp); bpp);
_cogl_bitmap_unmap (bmp); _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 */ /* Send data to GL */
ctx->texture_driver->upload_subregion_to_gl (ctx, status = ctx->texture_driver->upload_subregion_to_gl (ctx,
GL_TEXTURE_2D, GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE, FALSE,
@ -551,9 +584,12 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
width, height, width, height,
bmp, bmp,
gl_format, gl_format,
gl_type); gl_type,
error);
cogl_object_unref (bmp); cogl_object_unref (bmp);
return status;
} }
void void

View File

@ -40,6 +40,8 @@
#include "cogl-object-private.h" #include "cogl-object-private.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-opengl-private.h"
#include "cogl-util-gl-private.h"
#include "cogl-error-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -164,7 +166,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx,
pixels_bpp); pixels_bpp);
} }
static void static CoglBool
_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -177,13 +179,26 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
int height, int height,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
uint8_t *data; uint8_t *data;
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); 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 */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (ctx, prep_gl_for_pixels_upload_full (ctx,
@ -195,17 +210,26 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( ctx, glTexSubImage2D (gl_target, 0, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexSubImage2D (gl_target, 0,
dst_x, dst_y, dst_x, dst_y,
width, height, width, height,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); data);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
status = FALSE;
_cogl_bitmap_gl_unbind (source_bmp); _cogl_bitmap_gl_unbind (source_bmp);
return status;
} }
static void static CoglBool
_cogl_texture_driver_upload_to_gl (CoglContext *ctx, _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -213,13 +237,18 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
uint8_t *data; uint8_t *data;
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); 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 */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (ctx, prep_gl_for_pixels_upload_full (ctx,
@ -228,19 +257,28 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( ctx, glTexImage2D (gl_target, 0, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage2D (gl_target, 0,
internal_gl_format, internal_gl_format,
cogl_bitmap_get_width (source_bmp), cogl_bitmap_get_width (source_bmp),
cogl_bitmap_get_height (source_bmp), cogl_bitmap_get_height (source_bmp),
0, 0,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); data);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
status = FALSE;
_cogl_bitmap_gl_unbind (source_bmp); _cogl_bitmap_gl_unbind (source_bmp);
return status;
} }
static void static CoglBool
_cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -250,13 +288,18 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
uint8_t *data; uint8_t *data;
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); 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 */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (ctx, prep_gl_for_pixels_upload_full (ctx,
@ -267,7 +310,11 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( ctx, glTexImage3D (gl_target, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (gl_target,
0, /* level */ 0, /* level */
internal_gl_format, internal_gl_format,
cogl_bitmap_get_width (source_bmp), cogl_bitmap_get_width (source_bmp),
@ -276,9 +323,14 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
0, 0,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); data);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
status = FALSE;
_cogl_bitmap_gl_unbind (source_bmp); _cogl_bitmap_gl_unbind (source_bmp);
return status;
} }
static CoglBool static CoglBool

View File

@ -40,6 +40,8 @@
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-object-private.h" #include "cogl-object-private.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-util-gl-private.h"
#include "cogl-error-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -140,7 +142,8 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx,
static CoglBitmap * static CoglBitmap *
prepare_bitmap_alignment_for_upload (CoglContext *ctx, prepare_bitmap_alignment_for_upload (CoglContext *ctx,
CoglBitmap *src_bmp) CoglBitmap *src_bmp,
CoglError **error)
{ {
CoglPixelFormat format = cogl_bitmap_get_format (src_bmp); CoglPixelFormat format = cogl_bitmap_get_format (src_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
@ -163,10 +166,10 @@ prepare_bitmap_alignment_for_upload (CoglContext *ctx,
/* Otherwise we need to copy the bitmap to pack the alignment /* Otherwise we need to copy the bitmap to pack the alignment
because GLES has no GL_ROW_LENGTH */ because GLES has no GL_ROW_LENGTH */
else 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, _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -179,13 +182,17 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
int height, int height,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
uint8_t *data; uint8_t *data;
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
CoglBitmap *slice_bmp; CoglBitmap *slice_bmp;
int rowstride; int rowstride;
GLenum gl_error;
CoglBool status = TRUE;
CoglError *internal_error = NULL;
/* If we have the GL_EXT_unpack_subimage extension then we can /* If we have the GL_EXT_unpack_subimage extension then we can
upload from subregions directly. Otherwise we may need to copy upload from subregions directly. Otherwise we may need to copy
@ -199,39 +206,67 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
_cogl_bitmap_new_with_malloc_buffer (ctx, _cogl_bitmap_new_with_malloc_buffer (ctx,
width, height, width, height,
source_format); source_format);
_cogl_bitmap_copy_subregion (source_bmp, if (!_cogl_bitmap_copy_subregion (source_bmp,
slice_bmp, slice_bmp,
src_x, src_y, src_x, src_y,
0, 0, /* dst_x/y */ 0, 0, /* dst_x/y */
width, height); width, height,
error))
{
cogl_object_unref (slice_bmp);
return FALSE;
}
src_x = src_y = 0; src_x = src_y = 0;
} }
else 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); rowstride = cogl_bitmap_get_rowstride (slice_bmp);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp); 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); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
GE( ctx, glTexSubImage2D (gl_target, 0, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexSubImage2D (gl_target, 0,
dst_x, dst_y, dst_x, dst_y,
width, height, width, height,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); data);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
status = FALSE;
_cogl_bitmap_gl_unbind (slice_bmp); _cogl_bitmap_gl_unbind (slice_bmp);
cogl_object_unref (slice_bmp); cogl_object_unref (slice_bmp);
return status;
} }
static void static CoglBool
_cogl_texture_driver_upload_to_gl (CoglContext *ctx, _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -239,7 +274,8 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); 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); int bmp_height = cogl_bitmap_get_height (source_bmp);
CoglBitmap *bmp; CoglBitmap *bmp;
uint8_t *data; 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); rowstride = cogl_bitmap_get_rowstride (bmp);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
@ -257,22 +298,36 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _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, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage2D (gl_target, 0,
internal_gl_format, internal_gl_format,
bmp_width, bmp_height, bmp_width, bmp_height,
0, 0,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); data);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
status = FALSE;
_cogl_bitmap_gl_unbind (bmp); _cogl_bitmap_gl_unbind (bmp);
cogl_object_unref (bmp); cogl_object_unref (bmp);
return status;
} }
static void static CoglBool
_cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
GLenum gl_target, GLenum gl_target,
GLuint gl_handle, GLuint gl_handle,
@ -282,7 +337,8 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
CoglBitmap *source_bmp, CoglBitmap *source_bmp,
GLint internal_gl_format, GLint internal_gl_format,
GLuint source_gl_format, GLuint source_gl_format,
GLuint source_gl_type) GLuint source_gl_type,
CoglError **error)
{ {
CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); 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_width = cogl_bitmap_get_width (source_bmp);
int bmp_height = cogl_bitmap_get_height (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp);
uint8_t *data; uint8_t *data;
GLenum gl_error;
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
@ -309,7 +366,11 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
/* Initialize the texture with empty data and then upload each /* Initialize the texture with empty data and then upload each
image with a sub-region update */ image with a sub-region update */
GE( ctx, glTexImage3D (gl_target, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (gl_target,
0, /* level */ 0, /* level */
internal_gl_format, internal_gl_format,
bmp_width, bmp_width,
@ -318,7 +379,10 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
0, 0,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
NULL) ); NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
return FALSE;
bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
bmp_width, bmp_width,
@ -327,17 +391,31 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
for (i = 0; i < depth; i++) for (i = 0; i < depth; i++)
{ {
_cogl_bitmap_copy_subregion (source_bmp, if (!_cogl_bitmap_copy_subregion (source_bmp,
bmp, bmp,
0, image_height * i, 0, image_height * i,
0, 0, 0, 0,
bmp_width, bmp_width,
height); height,
error))
{
cogl_object_unref (bmp);
return FALSE;
}
data = _cogl_bitmap_gl_bind (bmp, 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, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexSubImage3D (gl_target,
0, /* level */ 0, /* level */
0, /* xoffset */ 0, /* xoffset */
0, /* yoffset */ 0, /* yoffset */
@ -347,7 +425,14 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
1, /* depth */ 1, /* depth */
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); 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); _cogl_bitmap_gl_unbind (bmp);
} }
@ -356,11 +441,17 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
} }
else 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); _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);
GE( ctx, glTexImage3D (gl_target, /* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (gl_target,
0, /* level */ 0, /* level */
internal_gl_format, internal_gl_format,
bmp_width, bmp_width,
@ -369,10 +460,18 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
0, 0,
source_gl_format, source_gl_format,
source_gl_type, source_gl_type,
data) ); 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); _cogl_bitmap_gl_unbind (source_bmp);
} }
return TRUE;
} }
/* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead /* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead

View File

@ -93,7 +93,7 @@ _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d);
void void
_cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d); _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d);
void CoglBool
_cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
CoglBitmap *bitmap, CoglBitmap *bitmap,
int dst_x, int dst_x,
@ -101,7 +101,8 @@ _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
int src_x, int src_x,
int src_y, int src_y,
int width, int width,
int height); int height,
CoglError **error);
void void
_cogl_texture_2d_nop_get_data (CoglTexture2D *tex_2d, _cogl_texture_2d_nop_get_data (CoglTexture2D *tex_2d,

View File

@ -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, _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
CoglBitmap *bitmap, CoglBitmap *bitmap,
int dst_x, int dst_x,
@ -143,8 +143,10 @@ _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
int src_x, int src_x,
int src_y, int src_y,
int width, int width,
int height) int height,
CoglError **error)
{ {
return TRUE;
} }
void void

View File

@ -682,12 +682,17 @@ _cogl_texture_pixmap_x11_set_region (CoglTexture *tex,
int src_y, int src_y,
int dst_x, int dst_x,
int dst_y, int dst_y,
unsigned int dst_width, int dst_width,
unsigned int dst_height, int dst_height,
CoglBitmap *bmp) CoglBitmap *bmp,
CoglError **error)
{ {
/* This doesn't make much sense for texture from pixmap so it's not /* This doesn't make much sense for texture from pixmap so it's not
supported */ supported */
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Explicitly setting a region of a TFP texture unsupported");
return FALSE; return FALSE;
} }

View File

@ -749,6 +749,7 @@ cogl_buffer_usage_hint_get_type
<FILE>cogl-attribute-buffer</FILE> <FILE>cogl-attribute-buffer</FILE>
<TITLE>CoglAttributeBuffer: Buffers of vertex attributes</TITLE> <TITLE>CoglAttributeBuffer: Buffers of vertex attributes</TITLE>
CoglAttributeBuffer CoglAttributeBuffer
cogl_attribute_buffer_new_with_size
cogl_attribute_buffer_new cogl_attribute_buffer_new
cogl_is_attribute_buffer cogl_is_attribute_buffer
</SECTION> </SECTION>

View File

@ -65,7 +65,8 @@ test_map_buffer_range (void)
sizeof (vertex_data[0]) * 2, sizeof (vertex_data[0]) * 2,
sizeof (vertex_data[0]), sizeof (vertex_data[0]),
COGL_BUFFER_ACCESS_WRITE, 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); g_assert (data != NULL);
data->x = vertex_data[2].x; data->x = vertex_data[2].x;