From 739b460c7a16693fb98fea5af4dc0daa9688c47a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 28 Jul 2009 00:37:11 +0100 Subject: [PATCH] Improve cogl-texture maintainability by moving 90% into cogl/common This splits the limited components that differed between cogl/{gl,gles}/cogl-texture.c into new {gl,gles}/cogl-texture-driver.c files and the rest that can now be shared into cogl/common/cogl-texture.c --- common/Makefile.am | 3 + common/cogl-internal.h | 1 + common/cogl-texture-driver.h | 157 ++ {gl => common}/cogl-texture-private.h | 12 +- {gl => common}/cogl-texture.c | 474 +----- gl/Makefile.am | 3 +- gl/cogl-texture-driver.c | 454 ++++++ gles/Makefile.am | 3 +- gles/cogl-gles2-wrapper.h | 1 + gles/cogl-texture-driver.c | 481 ++++++ gles/cogl-texture-private.h | 144 -- gles/cogl-texture.c | 2066 ------------------------- 12 files changed, 1188 insertions(+), 2611 deletions(-) create mode 100644 common/cogl-texture-driver.h rename {gl => common}/cogl-texture-private.h (94%) rename {gl => common}/cogl-texture.c (78%) create mode 100644 gl/cogl-texture-driver.c create mode 100644 gles/cogl-texture-driver.c delete mode 100644 gles/cogl-texture-private.h delete mode 100644 gles/cogl-texture.c diff --git a/common/Makefile.am b/common/Makefile.am index a9b9a13a6..f4f79f262 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -84,6 +84,9 @@ libclutter_cogl_common_la_SOURCES = \ cogl-blend-string.c \ cogl-blend-string.h \ cogl-debug.c \ + cogl-texture-private.h \ + cogl-texture-driver.h \ + cogl-texture.c \ $(NULL) EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in diff --git a/common/cogl-internal.h b/common/cogl-internal.h index 980e2a886..b488c5633 100644 --- a/common/cogl-internal.h +++ b/common/cogl-internal.h @@ -25,6 +25,7 @@ #define __COGL_INTERNAL_H #include "cogl-debug.h" +#include "cogl-types.h" #ifdef HAVE_COGL_GLES2 typedef enum { diff --git a/common/cogl-texture-driver.h b/common/cogl-texture-driver.h new file mode 100644 index 000000000..f2443d0bc --- /dev/null +++ b/common/cogl-texture-driver.h @@ -0,0 +1,157 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __COGL_TEXTURE_DRIVER_H +#define __COGL_TEXTURE_DRIVER_H + +/* + * Basically just a wrapper around glBindTexture, but the GLES2 backend + * for example also wants to know about the internal format so it can + * identify when alpha only textures are bound. + */ +void +_cogl_texture_driver_bind (GLenum gl_target, GLuint gl_handle, GLenum gl_intformat); + +/* + * This sets up the glPixelStore state for an upload to a destination with + * the same size, and with no offset. + */ +/* NB: GLES can't upload a sub region of pixel data from a larger source + * buffer which is why this interface is limited. The GL driver has a more + * flexible version of this function that is uses internally */ +void +_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride, + int pixels_bpp); + +/* + * This uploads a sub-region from source_bmp to a single GL texture handle (i.e + * a single CoglTexture slice) + * + * It also updates the array of tex->first_pixels[slice_index] if + * dst_{x,y} == 0 + * + * The driver abstraction is in place because GLES doesn't support the pixel + * store options required to source from a subregion, so for GLES we have + * to manually create a transient source bitmap. + * + * XXX: sorry for the ridiculous number of arguments :-( + */ +void +_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglBitmap *source_bmp, + GLuint source_gl_format, + GLuint source_gl_type, + GLuint gl_handle); + +/* + * This sets up the glPixelStore state for an download to a destination with + * the same size, and with no offset. + */ +/* NB: GLES can't download pixel data into a sub region of a larger destination + * buffer, the GL driver has a more flexible version of this function that it + * uses internally. */ +void +_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, + int pixels_bpp); + +/* + * This driver abstraction is in place because GLES doesn't have a sane way to + * download data from a texture so you litterally render the texture to the + * backbuffer, and retrive the data using glReadPixels :-( + */ +gboolean +_cogl_texture_driver_download_from_gl (CoglTexture *tex, + CoglBitmap *target_bmp, + GLuint target_gl_format, + GLuint target_gl_type); + +/* + * It may depend on the driver as to what texture sizes are supported... + */ +gboolean +_cogl_texture_driver_size_supported (GLenum gl_target, + GLenum gl_format, + GLenum gl_type, + int width, + int height); + +/* + * This driver abstraction is needed because GLES doesn't support setting + * a texture border color. + */ +void +_cogl_texture_driver_try_setting_gl_border_color ( + GLuint gl_target, + const GLfloat *transparent_color); + +/* + * XXX: this should live in cogl/{gl,gles}/cogl.c + */ +gboolean +_cogl_pixel_format_from_gl_internal (GLenum gl_int_format, + CoglPixelFormat *out_format); + +/* + * XXX: this should live in cogl/{gl,gles}/cogl.c + */ +CoglPixelFormat +_cogl_pixel_format_to_gl (CoglPixelFormat format, + GLenum *out_glintformat, + GLenum *out_glformat, + GLenum *out_gltype); + +/* + * It may depend on the driver as to what texture targets may be used when + * creating a foreign texture. E.g. OpenGL supports ARB_texture_rectangle + * but GLES doesn't + */ +gboolean +_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target); + +/* + * glGenerateMipmap semantics may need to be emulated for some drivers. E.g. by + * enabling auto mipmap generation an re-loading a number of known texels. + */ +void +_cogl_texture_driver_gl_generate_mipmaps (GLenum texture_target); + +/* + * The driver may impose constraints on what formats can be used to store + * texture data read from textures. For example GLES currently only supports + * RGBA_8888, and so we need to manually convert the data if the final + * destination has another format. + */ +CoglPixelFormat +_cogl_texture_driver_find_best_gl_get_data_format ( + CoglPixelFormat format, + GLenum *closest_gl_format, + GLenum *closest_gl_type); + +#endif /* __COGL_TEXTURE_DRIVER_H */ + diff --git a/gl/cogl-texture-private.h b/common/cogl-texture-private.h similarity index 94% rename from gl/cogl-texture-private.h rename to common/cogl-texture-private.h index 6a2ed7e39..bc610b671 100644 --- a/gl/cogl-texture-private.h +++ b/common/cogl-texture-private.h @@ -21,8 +21,8 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __COGL_TEXTURE_H -#define __COGL_TEXTURE_H +#ifndef __COGL_TEXTURE_PRIVATE_H +#define __COGL_TEXTURE_PRIVATE_H #include "cogl-bitmap-private.h" #include "cogl-handle.h" @@ -142,4 +142,10 @@ _cogl_span_iter_end (CoglSpanIter *iter); void _cogl_span_iter_next (CoglSpanIter *iter); -#endif /* __COGL_TEXTURE_H */ +void +_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); + +void +_cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride); + +#endif /* __COGL_TEXTURE_PRIVATE_H */ diff --git a/gl/cogl-texture.c b/common/cogl-texture.c similarity index 78% rename from gl/cogl-texture.c rename to common/cogl-texture.c index 20000ec35..440cf4565 100644 --- a/gl/cogl-texture.c +++ b/common/cogl-texture.c @@ -36,6 +36,7 @@ #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" +#include "cogl-texture-driver.h" #include "cogl-material.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -45,22 +46,6 @@ #include #include -#ifdef HAVE_COGL_GL - -#define glDrawRangeElements ctx->pf_glDrawRangeElements -#define glActiveTexture ctx->pf_glActiveTexture -#define glClientActiveTexture ctx->pf_glClientActiveTexture -#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT - -#else - -/* GLES doesn't have glDrawRangeElements, so we simply pretend it does - * but that it makes no use of the start, end constraints: */ -#define glDrawRangeElements(mode, start, end, count, type, indices) \ - glDrawElements (mode, count, type, indices) - -#endif - static void _cogl_texture_free (CoglTexture *tex); COGL_HANDLE_DEFINE (Texture, texture); @@ -162,17 +147,9 @@ _cogl_span_iter_end (CoglSpanIter *iter) return iter->pos >= iter->cover_end; } -static void -prep_for_gl_pixels_upload (gint pixels_rowstride, - gint pixels_src_x, - gint pixels_src_y, - gint pixels_bpp) +void +_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride) { - GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); - - GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); - GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); - if (!(pixels_rowstride & 0x7)) GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) ); else if (!(pixels_rowstride & 0x3)) @@ -183,17 +160,9 @@ prep_for_gl_pixels_upload (gint pixels_rowstride, GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) ); } -static void -prep_for_gl_pixels_download (gint pixels_rowstride, - gint pixels_src_x, - gint pixels_src_y, - gint pixels_bpp) +void +_cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride) { - GE( glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); - - GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); - GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); - if (!(pixels_rowstride & 0x7)) GE( glPixelStorei (GL_PACK_ALIGNMENT, 8) ); else if (!(pixels_rowstride & 0x3)) @@ -262,11 +231,18 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Pick the gl texture object handle */ gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); - /* Setup gl alignment to match rowstride and top-left corner */ - prep_for_gl_pixels_upload (tex->bitmap.rowstride, - x_span->start, - y_span->start, - bpp); + _cogl_texture_driver_upload_subregion_to_gl ( + tex, + x_span->start, /* src x */ + y_span->start, /* src y */ + 0, /* dst x */ + 0, /* dst y */ + x_span->size - x_span->waste, /* width */ + y_span->size - y_span->waste, /* height */ + &tex->bitmap, + tex->gl_format, + tex->gl_type, + gl_handle); /* Keep a copy of the first pixel if needed */ if (tex->first_pixels) @@ -279,17 +255,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) tex->first_pixels[slice_num].gl_type = tex->gl_type; } - /* Upload new image data */ - GE( glBindTexture (tex->gl_target, gl_handle) ); - - GE( glTexSubImage2D (tex->gl_target, 0, - 0, - 0, - x_span->size - x_span->waste, - y_span->size - y_span->waste, - tex->gl_format, tex->gl_type, - tex->bitmap.data) ); - /* Fill the waste with a copies of the rightmost pixels */ if (x_span->waste > 0) { @@ -309,10 +274,9 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) src += tex->bitmap.rowstride; } - prep_for_gl_pixels_upload (x_span->waste * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); + _cogl_texture_driver_prep_gl_for_pixels_upload ( + x_span->waste * bpp, + bpp); GE( glTexSubImage2D (tex->gl_target, 0, x_span->size - x_span->waste, @@ -344,10 +308,9 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) } } - prep_for_gl_pixels_upload (x_span->size * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); + _cogl_texture_driver_prep_gl_for_pixels_upload ( + x_span->size * bpp, + bpp); GE( glTexSubImage2D (tex->gl_target, 0, 0, @@ -368,95 +331,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) return TRUE; } -static gboolean -_cogl_texture_download_from_gl (CoglTexture *tex, - CoglBitmap *target_bmp, - GLuint target_gl_format, - GLuint target_gl_type) -{ - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - GLuint gl_handle; - gint bpp; - gint x,y; - CoglBitmap slice_bmp; - - bpp = _cogl_get_format_bpp (target_bmp->format); - - /* Iterate vertical slices */ - for (y = 0; y < tex->slice_y_spans->len; ++y) - { - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); - - /* Iterate horizontal slices */ - for (x = 0; x < tex->slice_x_spans->len; ++x) - { - /*if (x != 0 || y != 1) continue;*/ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); - - /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); - - /* If there's any waste we need to copy manually - (no glGetTexSubImage) */ - - if (y_span->waste != 0 || x_span->waste != 0) - { - /* Setup temp bitmap for slice subregion */ - slice_bmp.format = target_bmp->format; - slice_bmp.width = x_span->size; - slice_bmp.height = y_span->size; - slice_bmp.rowstride = bpp * slice_bmp.width; - slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * - slice_bmp.height); - - /* Setup gl alignment to 0,0 top-left corner */ - prep_for_gl_pixels_download (slice_bmp.rowstride, 0, 0, bpp); - - /* Download slice image data into temp bmp */ - GE( glBindTexture (tex->gl_target, gl_handle) ); - - GE (glGetTexImage (tex->gl_target, - 0, /* level */ - target_gl_format, - target_gl_type, - slice_bmp.data) ); - - /* Copy portion of slice from temp to target bmp */ - _cogl_bitmap_copy_subregion (&slice_bmp, - target_bmp, - 0, 0, - x_span->start, - y_span->start, - x_span->size - x_span->waste, - y_span->size - y_span->waste); - /* Free temp bitmap */ - g_free (slice_bmp.data); - } - else - { - GLvoid *dst = target_bmp->data - + x_span->start * bpp - + y_span->start * target_bmp->rowstride; - - prep_for_gl_pixels_download (target_bmp->rowstride, 0, 0, bpp); - - /* Download slice image data */ - GE( glBindTexture (tex->gl_target, gl_handle) ); - - GE( glGetTexImage (tex->gl_target, - 0, /* level */ - target_gl_format, - target_gl_type, - dst) ); - } - } - } - - return TRUE; -} - static gboolean _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, gint src_x, @@ -529,27 +403,29 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, x_iter.index); /* Pick intersection width and height */ - inter_w = (x_iter.intersect_end - - x_iter.intersect_start); - inter_h = (y_iter.intersect_end - - y_iter.intersect_start); + inter_w = (x_iter.intersect_end - x_iter.intersect_start); + inter_h = (y_iter.intersect_end - y_iter.intersect_start); /* Localize intersection top-left corner to slice*/ - local_x = (x_iter.intersect_start - - x_iter.pos); - local_y = (y_iter.intersect_start - - y_iter.pos); + local_x = (x_iter.intersect_start - x_iter.pos); + local_y = (y_iter.intersect_start - y_iter.pos); slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; /* Pick slice GL handle */ gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); - /* Setup gl alignment to match rowstride and top-left corner */ - prep_for_gl_pixels_upload (source_bmp->rowstride, - source_x, - source_y, - bpp); + _cogl_texture_driver_upload_subregion_to_gl (tex, + source_x, + source_y, + local_x, /* dst x */ + local_y, /* dst x */ + inter_w, /* width */ + inter_h, /* height */ + source_bmp, + source_gl_format, + source_gl_type, + gl_handle); /* Keep a copy of the first pixel if needed */ if (tex->first_pixels && local_x == 0 && local_y == 0) @@ -562,16 +438,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, tex->first_pixels[slice_num].gl_type = source_gl_type; } - /* Upload new image data */ - GE( glBindTexture (tex->gl_target, gl_handle) ); - - GE( glTexSubImage2D (tex->gl_target, 0, - local_x, local_y, - inter_w, inter_h, - source_gl_format, - source_gl_type, - source_bmp->data) ); - /* If the x_span is sliced and the upload touches the rightmost pixels then fill the waste with copies of the pixels */ @@ -603,10 +469,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, src += source_bmp->rowstride; } - prep_for_gl_pixels_upload (x_span->waste * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); + _cogl_texture_driver_prep_gl_for_pixels_upload ( + x_span->waste * bpp, + bpp); GE( glTexSubImage2D (tex->gl_target, 0, x_span->size - x_span->waste, @@ -655,10 +520,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, } } - prep_for_gl_pixels_upload (copy_width * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); + _cogl_texture_driver_prep_gl_for_pixels_upload ( + copy_width * bpp, + bpp); GE( glTexSubImage2D (tex->gl_target, 0, local_x, @@ -739,7 +603,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, if (size_to_fill > span.size) { /* Not yet - add a span of this size */ - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + span.start += span.size; size_to_fill -= span.size; n_spans++; @@ -748,7 +614,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, { /* Yes and waste is small enough */ span.waste = span.size - size_to_fill; - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + return ++n_spans; } else @@ -766,35 +634,6 @@ _cogl_pot_slices_for_size (gint size_to_fill, return 0; } -static gboolean -_cogl_texture_size_supported (GLenum gl_target, - GLenum gl_format, - GLenum gl_type, - int width, - int height) -{ - if (gl_target == GL_TEXTURE_2D) - { - /* Proxy texture allows for a quick check for supported size */ - - GLint new_width = 0; - - GE( glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA, - width, height, 0 /* border */, - gl_format, gl_type, NULL) ); - - GE( glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, - GL_TEXTURE_WIDTH, &new_width) ); - - return new_width != 0; - } - else - { - /* not used */ - return 0; - } -} - void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode) @@ -863,11 +702,11 @@ _cogl_texture_slices_create (CoglTexture *tex) CoglTexSliceSpan span; /* Check if size supported else bail out */ - if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + if (!_cogl_texture_driver_size_supported (tex->gl_target, + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { return FALSE; } @@ -897,11 +736,11 @@ _cogl_texture_slices_create (CoglTexture *tex) else { /* Decrease the size of largest slice until supported by GL */ - while (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + while (!_cogl_texture_driver_size_supported (tex->gl_target, + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { /* Alternate between width and height */ if (max_width > max_height) @@ -951,7 +790,7 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); /* Allocate some space to store a copy of the first pixel of each - slice. This is only needed to glGenerateMipmap (which is part of + slice. This is only needed if glGenerateMipmap (which is part of the FBO extension) is not available */ if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) tex->first_pixels = NULL; @@ -984,14 +823,12 @@ _cogl_texture_slices_create (CoglTexture *tex) y_span->size - y_span->waste); /* Setup texture parameters */ - GE( glBindTexture (tex->gl_target, - gl_handles[y * n_x_slices + x]) ); + GE( _cogl_texture_driver_bind (tex->gl_target, + gl_handles[y * n_x_slices + x], + tex->gl_intformat) ); - /* Use a transparent border color so that we can leave the - color buffer alone when using texture co-ordinates - outside of the texture */ - GE( glTexParameterfv (tex->gl_target, GL_TEXTURE_BORDER_COLOR, - transparent_color) ); + _cogl_texture_driver_try_setting_gl_border_color (tex->gl_target, + transparent_color); /* Pass NULL data to init size and internal format */ GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, @@ -1041,153 +878,6 @@ _cogl_texture_span_has_waste (CoglTexture *tex, return (x_span->waste || y_span->waste) ? TRUE : FALSE; } -static gboolean -_cogl_pixel_format_from_gl_internal (GLenum gl_int_format, - CoglPixelFormat *out_format) -{ - /* It doesn't really matter we convert to exact same - format (some have no cogl match anyway) since format - is re-matched against cogl when getting or setting - texture image data. - */ - - switch (gl_int_format) - { - case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: - case GL_ALPHA12: case GL_ALPHA16: - - *out_format = COGL_PIXEL_FORMAT_A_8; - return TRUE; - - case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: - case GL_LUMINANCE12: case GL_LUMINANCE16: - - *out_format = COGL_PIXEL_FORMAT_G_8; - return TRUE; - - case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8: - case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2: - - *out_format = COGL_PIXEL_FORMAT_RGB_888; - return TRUE; - - case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: - case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: - - *out_format = COGL_PIXEL_FORMAT_RGBA_8888; - return TRUE; - } - - return FALSE; -} - -static CoglPixelFormat -_cogl_pixel_format_to_gl (CoglPixelFormat format, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype) -{ - CoglPixelFormat required_format; - GLenum glintformat = 0; - GLenum glformat = 0; - GLenum gltype = 0; - - /* FIXME: check YUV support */ - - required_format = format; - - /* Find GL equivalents */ - switch (format & COGL_UNPREMULT_MASK) - { - case COGL_PIXEL_FORMAT_A_8: - glintformat = GL_ALPHA; - glformat = GL_ALPHA; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_G_8: - glintformat = GL_LUMINANCE; - glformat = GL_LUMINANCE; - gltype = GL_UNSIGNED_BYTE; - break; - - case COGL_PIXEL_FORMAT_RGB_888: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_BGR_888: - glintformat = GL_RGB; - glformat = GL_BGR; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_RGBA_8888: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_BGRA_8888: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_UNSIGNED_BYTE; - break; - - /* The following two types of channel ordering - * have no GL equivalent unless defined using - * system word byte ordering */ - case COGL_PIXEL_FORMAT_ARGB_8888: - glintformat = GL_RGBA; - glformat = GL_BGRA; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - gltype = GL_UNSIGNED_INT_8_8_8_8; -#else - gltype = GL_UNSIGNED_INT_8_8_8_8_REV; -#endif - break; - - case COGL_PIXEL_FORMAT_ABGR_8888: - glintformat = GL_RGBA; - glformat = GL_RGBA; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - gltype = GL_UNSIGNED_INT_8_8_8_8; -#else - gltype = GL_UNSIGNED_INT_8_8_8_8_REV; -#endif - break; - - /* The following three types of channel ordering - * are always defined using system word byte - * ordering (even according to GLES spec) */ - case COGL_PIXEL_FORMAT_RGB_565: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - case COGL_PIXEL_FORMAT_RGBA_4444: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case COGL_PIXEL_FORMAT_RGBA_5551: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_5_5_5_1; - break; - - /* FIXME: check extensions for YUV support */ - default: - break; - } - - if (out_glintformat != NULL) - *out_glintformat = glintformat; - if (out_glformat != NULL) - *out_glformat = glformat; - if (out_gltype != NULL) - *out_gltype = gltype; - - return required_format; -} - static gboolean _cogl_texture_bitmap_prepare (CoglTexture *tex, CoglPixelFormat internal_format) @@ -1496,14 +1186,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, CoglTexSliceSpan x_span; CoglTexSliceSpan y_span; - /* GL_ARB_texture_rectangle textures are supported if they are - created from foreign because some chipsets have trouble with - GL_ARB_texture_non_power_of_two. There is no Cogl call to create - them directly to emphasize the fact that they don't work fully - (for example, no mipmapping and complicated shader support) */ - - /* Allow 2-dimensional or rectangle textures only */ - if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB) + if (!_cogl_texture_driver_allows_foreign_gl_target (gl_target)) return COGL_INVALID_HANDLE; /* Make sure it is a valid GL texture object */ @@ -1520,6 +1203,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, /* Obtain texture parameters (only level 0 we are interested in) */ +#if HAVE_COGL_GL GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_COMPRESSED, &gl_compressed) ); @@ -1536,6 +1220,10 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_HEIGHT, &gl_height) ); +#else + gl_width = width + x_pot_waste; + gl_height = height + y_pot_waste; +#endif GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, @@ -1796,7 +1484,7 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle) /* glGenerateMipmap is defined in the FBO extension */ if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) - GE( glGenerateMipmap (tex->gl_target) ); + _cogl_texture_driver_gl_generate_mipmaps (tex->gl_target); else if (tex->first_pixels) { CoglTexturePixel *pixel = tex->first_pixels + i; @@ -1935,12 +1623,10 @@ cogl_texture_get_data (CoglHandle handle, byte_size = tex->bitmap.height * rowstride; if (data == NULL) return byte_size; - /* Find closest format that's supported by GL */ - closest_format = _cogl_pixel_format_to_gl (format, - NULL, /* don't need */ - &closest_gl_format, - &closest_gl_type); - + closest_format = + _cogl_texture_driver_find_best_gl_get_data_format (format, + &closest_gl_format, + &closest_gl_type); closest_bpp = _cogl_get_format_bpp (closest_format); /* Is the requested format supported? */ @@ -1963,9 +1649,9 @@ cogl_texture_get_data (CoglHandle handle, } /* Retrieve data from slices */ - _cogl_texture_download_from_gl (tex, &target_bmp, - closest_gl_format, - closest_gl_type); + _cogl_texture_driver_download_from_gl (tex, &target_bmp, + closest_gl_format, + closest_gl_type); /* Was intermediate used? */ if (closest_format != format) diff --git a/gl/Makefile.am b/gl/Makefile.am index 993ccaae9..cacafb8cb 100644 --- a/gl/Makefile.am +++ b/gl/Makefile.am @@ -20,7 +20,6 @@ cogl_headers = \ $(NULL) cogl_priv_headers = \ - cogl-texture-private.h \ cogl-fbo.h \ cogl-shader-private.h \ cogl-program.h \ @@ -30,7 +29,7 @@ cogl_priv_headers = \ cogl_sources = \ cogl.c \ cogl-primitives.c \ - cogl-texture.c \ + cogl-texture-driver.c \ cogl-fbo.c \ cogl-shader.c \ cogl-program.c \ diff --git a/gl/cogl-texture-driver.c b/gl/cogl-texture-driver.c new file mode 100644 index 000000000..53cd44b1c --- /dev/null +++ b/gl/cogl-texture-driver.c @@ -0,0 +1,454 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Matthew Allum + * Neil Roberts + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-util.h" +#include "cogl-bitmap.h" +#include "cogl-bitmap-private.h" +#include "cogl-texture-private.h" +#include "cogl-material.h" +#include "cogl-context.h" +#include "cogl-handle.h" +#include "cogl-primitives.h" + +#include +#include +#include + +#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT + +void +_cogl_texture_driver_bind (GLenum gl_target, + GLuint gl_handle, + GLenum gl_intformat) +{ + GE (glBindTexture (gl_target, gl_handle)); +} + +/* OpenGL - unlike GLES - can upload a sub region of pixel data from a larger + * source buffer */ +static void +prep_gl_for_pixels_upload_full (int pixels_rowstride, + int pixels_src_x, + int pixels_src_y, + int pixels_bpp) +{ + GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); + + GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); + GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); + + _cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride); +} + +void +_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride, + int pixels_bpp) +{ + prep_gl_for_pixels_upload_full (pixels_rowstride, 0, 0, pixels_bpp); +} + +/* OpenGL - unlike GLES - can download pixel data into a sub region of + * a larger destination buffer */ +static void +prep_gl_for_pixels_download_full (int pixels_rowstride, + int pixels_src_x, + int pixels_src_y, + int pixels_bpp) +{ + GE( glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); + + GE( glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); + GE( glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); + + _cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride); +} + +void +_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, + int pixels_bpp) +{ + prep_gl_for_pixels_download_full (pixels_rowstride, 0, 0, pixels_bpp); +} + +void +_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglBitmap *source_bmp, + GLuint source_gl_format, + GLuint source_gl_type, + GLuint gl_handle) +{ + int bpp = _cogl_get_format_bpp (source_bmp->format); + + /* Setup gl alignment to match rowstride and top-left corner */ + prep_gl_for_pixels_upload_full (source_bmp->rowstride, + src_x, + src_y, + bpp); + + /* Upload new image data */ + GE( _cogl_texture_driver_bind (tex->gl_target, + gl_handle, tex->gl_intformat) ); + + GE( glTexSubImage2D (tex->gl_target, 0, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + source_bmp->data) ); +} + +gboolean +_cogl_texture_driver_download_from_gl (CoglTexture *tex, + CoglBitmap *target_bmp, + GLuint target_gl_format, + GLuint target_gl_type) +{ + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + GLuint gl_handle; + gint bpp; + gint x,y; + CoglBitmap slice_bmp; + + bpp = _cogl_get_format_bpp (target_bmp->format); + + /* Iterate vertical slices */ + for (y = 0; y < tex->slice_y_spans->len; ++y) + { + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); + + /* Iterate horizontal slices */ + for (x = 0; x < tex->slice_x_spans->len; ++x) + { + /*if (x != 0 || y != 1) continue;*/ + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); + + /* Pick the gl texture object handle */ + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, + y * tex->slice_x_spans->len + x); + + /* If there's any waste we need to copy manually + (no glGetTexSubImage) */ + + if (y_span->waste != 0 || x_span->waste != 0) + { + /* Setup temp bitmap for slice subregion */ + slice_bmp.format = target_bmp->format; + slice_bmp.width = x_span->size; + slice_bmp.height = y_span->size; + slice_bmp.rowstride = bpp * slice_bmp.width; + slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * + slice_bmp.height); + + /* Setup gl alignment to 0,0 top-left corner */ + _cogl_texture_driver_prep_gl_for_pixels_download ( + slice_bmp.rowstride, + bpp); + + /* Download slice image data into temp bmp */ + GE( glBindTexture (tex->gl_target, gl_handle) ); + + GE (glGetTexImage (tex->gl_target, + 0, /* level */ + target_gl_format, + target_gl_type, + slice_bmp.data) ); + + /* Copy portion of slice from temp to target bmp */ + _cogl_bitmap_copy_subregion (&slice_bmp, + target_bmp, + 0, 0, + x_span->start, + y_span->start, + x_span->size - x_span->waste, + y_span->size - y_span->waste); + /* Free temp bitmap */ + g_free (slice_bmp.data); + } + else + { + GLvoid *dst = target_bmp->data + + x_span->start * bpp + + y_span->start * target_bmp->rowstride; + + _cogl_texture_driver_prep_gl_for_pixels_download ( + target_bmp->rowstride, + bpp); + + /* Download slice image data */ + GE( glBindTexture (tex->gl_target, gl_handle) ); + + GE( glGetTexImage (tex->gl_target, + 0, /* level */ + target_gl_format, + target_gl_type, + dst) ); + } + } + } + + return TRUE; +} + +gboolean +_cogl_texture_driver_size_supported (GLenum gl_target, + GLenum gl_format, + GLenum gl_type, + int width, + int height) +{ + if (gl_target == GL_TEXTURE_2D) + { + /* Proxy texture allows for a quick check for supported size */ + + GLint new_width = 0; + + GE( glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA, + width, height, 0 /* border */, + gl_format, gl_type, NULL) ); + + GE( glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, + GL_TEXTURE_WIDTH, &new_width) ); + + return new_width != 0; + } + else + { + /* not used */ + return 0; + } +} + +void +_cogl_texture_driver_try_setting_gl_border_color ( + GLuint gl_target, + const GLfloat *transparent_color) +{ + /* Use a transparent border color so that we can leave the + color buffer alone when using texture co-ordinates + outside of the texture */ + GE( glTexParameterfv (gl_target, GL_TEXTURE_BORDER_COLOR, + transparent_color) ); +} + +gboolean +_cogl_pixel_format_from_gl_internal (GLenum gl_int_format, + CoglPixelFormat *out_format) +{ + /* It doesn't really matter we convert to exact same + format (some have no cogl match anyway) since format + is re-matched against cogl when getting or setting + texture image data. + */ + + switch (gl_int_format) + { + case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: + case GL_ALPHA12: case GL_ALPHA16: + + *out_format = COGL_PIXEL_FORMAT_A_8; + return TRUE; + + case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: + case GL_LUMINANCE12: case GL_LUMINANCE16: + + *out_format = COGL_PIXEL_FORMAT_G_8; + return TRUE; + + case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8: + case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2: + + *out_format = COGL_PIXEL_FORMAT_RGB_888; + return TRUE; + + case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: + case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: + + *out_format = COGL_PIXEL_FORMAT_RGBA_8888; + return TRUE; + } + + return FALSE; +} + +CoglPixelFormat +_cogl_pixel_format_to_gl (CoglPixelFormat format, + GLenum *out_glintformat, + GLenum *out_glformat, + GLenum *out_gltype) +{ + CoglPixelFormat required_format; + GLenum glintformat = 0; + GLenum glformat = 0; + GLenum gltype = 0; + + /* FIXME: check YUV support */ + + required_format = format; + + /* Find GL equivalents */ + switch (format & COGL_UNPREMULT_MASK) + { + case COGL_PIXEL_FORMAT_A_8: + glintformat = GL_ALPHA; + glformat = GL_ALPHA; + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_G_8: + glintformat = GL_LUMINANCE; + glformat = GL_LUMINANCE; + gltype = GL_UNSIGNED_BYTE; + break; + + case COGL_PIXEL_FORMAT_RGB_888: + glintformat = GL_RGB; + glformat = GL_RGB; + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_BGR_888: + glintformat = GL_RGB; + glformat = GL_BGR; + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_RGBA_8888: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_BGRA_8888: + glintformat = GL_RGBA; + glformat = GL_BGRA; + gltype = GL_UNSIGNED_BYTE; + break; + + /* The following two types of channel ordering + * have no GL equivalent unless defined using + * system word byte ordering */ + case COGL_PIXEL_FORMAT_ARGB_8888: + glintformat = GL_RGBA; + glformat = GL_BGRA; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + gltype = GL_UNSIGNED_INT_8_8_8_8; +#else + gltype = GL_UNSIGNED_INT_8_8_8_8_REV; +#endif + break; + + case COGL_PIXEL_FORMAT_ABGR_8888: + glintformat = GL_RGBA; + glformat = GL_RGBA; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + gltype = GL_UNSIGNED_INT_8_8_8_8; +#else + gltype = GL_UNSIGNED_INT_8_8_8_8_REV; +#endif + break; + + /* The following three types of channel ordering + * are always defined using system word byte + * ordering (even according to GLES spec) */ + case COGL_PIXEL_FORMAT_RGB_565: + glintformat = GL_RGB; + glformat = GL_RGB; + gltype = GL_UNSIGNED_SHORT_5_6_5; + break; + case COGL_PIXEL_FORMAT_RGBA_4444: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case COGL_PIXEL_FORMAT_RGBA_5551: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_SHORT_5_5_5_1; + break; + + /* FIXME: check extensions for YUV support */ + default: + break; + } + + if (out_glintformat != NULL) + *out_glintformat = glintformat; + if (out_glformat != NULL) + *out_glformat = glformat; + if (out_gltype != NULL) + *out_gltype = gltype; + + return required_format; +} + +gboolean +_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target) +{ + /* GL_ARB_texture_rectangle textures are supported if they are + created from foreign because some chipsets have trouble with + GL_ARB_texture_non_power_of_two. There is no Cogl call to create + them directly to emphasize the fact that they don't work fully + (for example, no mipmapping and complicated shader support) */ + + /* Allow 2-dimensional or rectangle textures only */ + if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB) + return FALSE; + + return TRUE; +} + +void +_cogl_texture_driver_gl_generate_mipmaps (GLenum gl_target) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + GE( glGenerateMipmap (gl_target) ); +} + +CoglPixelFormat +_cogl_texture_driver_find_best_gl_get_data_format ( + CoglPixelFormat format, + GLenum *closest_gl_format, + GLenum *closest_gl_type) +{ + /* Find closest format that's supported by GL */ + return _cogl_pixel_format_to_gl (format, + NULL, /* don't need */ + closest_gl_format, + closest_gl_type); +} + diff --git a/gles/Makefile.am b/gles/Makefile.am index 3d1ee4006..0172adc14 100644 --- a/gles/Makefile.am +++ b/gles/Makefile.am @@ -48,12 +48,11 @@ libclutter_cogl_gles_la_SOURCES = \ $(top_builddir)/clutter/cogl/cogl-texture.h \ $(top_builddir)/clutter/cogl/cogl-types.h \ $(top_builddir)/clutter/cogl/cogl-debug.h \ - cogl-texture-private.h \ cogl-fbo.h \ cogl-context.h \ cogl.c \ cogl-primitives.c \ - cogl-texture.c \ + cogl-texture-driver.c \ cogl-fbo.c \ cogl-context.c \ cogl-gles2-wrapper.h \ diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index e6c6a4c16..e81546031 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -24,6 +24,7 @@ #ifndef __COGL_GLES2_WRAPPER_H__ #define __COGL_GLES2_WRAPPER_H__ +#include "cogl.h" /* needed for gl header include */ #include "cogl-internal.h" G_BEGIN_DECLS diff --git a/gles/cogl-texture-driver.c b/gles/cogl-texture-driver.c new file mode 100644 index 000000000..7f5773b5f --- /dev/null +++ b/gles/cogl-texture-driver.c @@ -0,0 +1,481 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Matthew Allum + * Neil Roberts + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-util.h" +#include "cogl-bitmap.h" +#include "cogl-bitmap-private.h" +#include "cogl-texture-private.h" +#include "cogl-material.h" +#include "cogl-context.h" +#include "cogl-handle.h" +#include "cogl-primitives.h" + +#include +#include +#include + +#include "cogl-gles2-wrapper.h" + + +void +_cogl_texture_driver_bind (GLenum gl_target, + GLuint gl_handle, + GLenum gl_intformat) +{ + GE (cogl_gles2_wrapper_bind_texture (gl_target, gl_handle, gl_intformat)); +} + +void +_cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride, + int pixels_bpp) +{ + _cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride); +} + +void +_cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride, + int pixels_bpp) +{ + _cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride); +} + +void +_cogl_texture_driver_upload_subregion_to_gl (CoglTexture *tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height, + CoglBitmap *source_bmp, + GLuint source_gl_format, + GLuint source_gl_type, + GLuint gl_handle) +{ + int bpp = _cogl_get_format_bpp (source_bmp->format); + CoglBitmap slice_bmp; + + /* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_PIXELS + * or GL_UNPACK_SKIP_ROWS pixel store options so we can't directly source a + * sub-region from source_bmp, we need to use a transient bitmap instead. */ + + /* FIXME: optimize by not copying to intermediate slice bitmap when source + * rowstride = bpp * width and the texture image is not sliced */ + + /* Setup temp bitmap for slice subregion */ + slice_bmp.format = tex->bitmap.format; + slice_bmp.width = width; + slice_bmp.height = height; + slice_bmp.rowstride = bpp * slice_bmp.width; + slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.height); + + /* Setup gl alignment to match rowstride and top-left corner */ + _cogl_texture_driver_prep_gl_for_pixels_upload (slice_bmp.rowstride, + bpp); + + /* Copy subregion data */ + _cogl_bitmap_copy_subregion (source_bmp, + &slice_bmp, + src_x, + src_y, + 0, 0, + slice_bmp.width, + slice_bmp.height); + + /* Upload new image data */ + GE( _cogl_texture_driver_bind (tex->gl_target, + gl_handle, tex->gl_intformat) ); + + GE( glTexSubImage2D (tex->gl_target, 0, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + slice_bmp.data) ); + + /* Free temp bitmap */ + g_free (slice_bmp.data); +} + +static void +_cogl_texture_draw_and_read (CoglTexture *tex, + CoglBitmap *target_bmp, + GLint *viewport) +{ + gint bpp; + float rx1, ry1; + float rx2, ry2; + float tx1, ty1; + float tx2, ty2; + int bw, bh; + CoglBitmap rect_bmp; + CoglHandle handle; + + handle = (CoglHandle) tex; + bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); + + ry1 = 0; ry2 = 0; + ty1 = 0; ty2 = 0; + + /* Walk Y axis until whole bitmap height consumed */ + for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3]) + { + /* Rectangle Y coords */ + ry1 = ry2; + ry2 += (bh < viewport[3]) ? bh : viewport[3]; + + /* Normalized texture Y coords */ + ty1 = ty2; + ty2 = (ry2 / (float)tex->bitmap.height); + + rx1 = 0; rx2 = 0; + tx1 = 0; tx2 = 0; + + /* Walk X axis until whole bitmap width consumed */ + for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2]) + { + /* Rectangle X coords */ + rx1 = rx2; + rx2 += (bw < viewport[2]) ? bw : viewport[2]; + + /* Normalized texture X coords */ + tx1 = tx2; + tx2 = (rx2 / (float)tex->bitmap.width); + + /* Draw a portion of texture */ + cogl_rectangle_with_texture_coords (0, 0, + rx2 - rx1, + ry2 - ry1, + tx1, ty1, + tx2, ty2); + + /* Read into a temporary bitmap */ + rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; + rect_bmp.width = rx2 - rx1; + rect_bmp.height = ry2 - ry1; + rect_bmp.rowstride = bpp * rect_bmp.width; + rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * + rect_bmp.height); + + _cogl_texture_driver_prep_gl_for_pixels_download (rect_bmp.rowstride, + bpp); + GE( glReadPixels (viewport[0], viewport[1], + rect_bmp.width, + rect_bmp.height, + GL_RGBA, GL_UNSIGNED_BYTE, + rect_bmp.data) ); + + /* Copy to target bitmap */ + _cogl_bitmap_copy_subregion (&rect_bmp, + target_bmp, + 0,0, + rx1,ry1, + rect_bmp.width, + rect_bmp.height); + + /* Free temp bitmap */ + g_free (rect_bmp.data); + } + } +} + +gboolean +_cogl_texture_driver_download_from_gl (CoglTexture *tex, + CoglBitmap *target_bmp, + GLuint target_gl_format, + GLuint target_gl_type) +{ + gint bpp; + GLint viewport[4]; + CoglBitmap alpha_bmp; + CoglHandle prev_source; + + _COGL_GET_CONTEXT (ctx, FALSE); + + + bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); + + /* Viewport needs to have some size and be inside the window for this */ + GE( glGetIntegerv (GL_VIEWPORT, viewport) ); + + if (viewport[0] < 0 || viewport[1] < 0 || + viewport[2] <= 0 || viewport[3] <= 0) + return FALSE; + + /* Setup orthographic projection into current viewport + (0,0 in bottom-left corner to draw the texture + upside-down so we match the way glReadPixels works) */ + + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_push (); + _cogl_current_matrix_identity (); + + _cogl_current_matrix_ortho (0, (float)(viewport[2]), + 0, (float)(viewport[3]), + (float)(0), + (float)(100)); + + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_push (); + _cogl_current_matrix_identity (); + + /* Direct copy operation */ + + if (ctx->texture_download_material == COGL_INVALID_HANDLE) + { + ctx->texture_download_material = cogl_material_new (); + cogl_material_set_blend (ctx->texture_download_material, + "RGBA = ADD (SRC_COLOR, 0)", + NULL); + } + + prev_source = cogl_handle_ref (ctx->source_material); + cogl_set_source (ctx->texture_download_material); + + cogl_material_set_layer (ctx->texture_download_material, 0, tex); + + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE)", + NULL); + + _cogl_texture_draw_and_read (tex, target_bmp, viewport); + + /* Check whether texture has alpha and framebuffer not */ + /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer + still doesn't seem to have an alpha buffer. This might be just + a PowerVR issue. + GLint r_bits, g_bits, b_bits, a_bits; + GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); + GE( glGetIntegerv (GL_RED_BITS, &r_bits) ); + GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) ); + GE( 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 ((tex->bitmap.format & COGL_A_BIT)/* && a_bits == 0*/) + { + guchar *srcdata; + guchar *dstdata; + guchar *srcpixel; + guchar *dstpixel; + gint x,y; + + /* Create temp bitmap for alpha values */ + alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; + alpha_bmp.width = target_bmp->width; + alpha_bmp.height = target_bmp->height; + alpha_bmp.rowstride = bpp * alpha_bmp.width; + alpha_bmp.data = (guchar*) g_malloc (alpha_bmp.rowstride * + alpha_bmp.height); + + /* Draw alpha values into RGB channels */ + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE[A])", + NULL); + + _cogl_texture_draw_and_read (tex, &alpha_bmp, viewport); + + /* Copy temp R to target A */ + srcdata = alpha_bmp.data; + dstdata = target_bmp->data; + + for (y=0; yheight; ++y) + { + for (x=0; xwidth; ++x) + { + srcpixel = srcdata + x*bpp; + dstpixel = dstdata + x*bpp; + dstpixel[3] = srcpixel[0]; + } + srcdata += alpha_bmp.rowstride; + dstdata += target_bmp->rowstride; + } + + g_free (alpha_bmp.data); + } + + /* Restore old state */ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_pop (); + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_pop (); + + /* restore the original material */ + cogl_set_source (prev_source); + cogl_handle_unref (prev_source); + + return TRUE; +} + +gboolean +_cogl_texture_driver_size_supported (GLenum gl_target, + GLenum gl_format, + GLenum gl_type, + int width, + int height) +{ + return TRUE; +} + +void +_cogl_texture_driver_try_setting_gl_border_color ( + GLuint gl_target, + const GLfloat *transparent_color) +{ + /* FAIL! */ +} + +gboolean +_cogl_pixel_format_from_gl_internal (GLenum gl_int_format, + CoglPixelFormat *out_format) +{ + return TRUE; +} + +CoglPixelFormat +_cogl_pixel_format_to_gl (CoglPixelFormat format, + GLenum *out_glintformat, + GLenum *out_glformat, + GLenum *out_gltype) +{ + CoglPixelFormat required_format; + GLenum glintformat = 0; + GLenum glformat = 0; + GLenum gltype = 0; + + /* FIXME: check YUV support */ + + required_format = format; + + /* Find GL equivalents */ + switch (format & COGL_UNPREMULT_MASK) + { + case COGL_PIXEL_FORMAT_A_8: + glintformat = GL_ALPHA; + glformat = GL_ALPHA; + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_G_8: + glintformat = GL_LUMINANCE; + glformat = GL_LUMINANCE; + gltype = GL_UNSIGNED_BYTE; + break; + + /* Just one 24-bit ordering supported */ + case COGL_PIXEL_FORMAT_RGB_888: + case COGL_PIXEL_FORMAT_BGR_888: + glintformat = GL_RGB; + glformat = GL_RGB; + gltype = GL_UNSIGNED_BYTE; + required_format = COGL_PIXEL_FORMAT_RGB_888; + break; + + /* Just one 32-bit ordering supported */ + case COGL_PIXEL_FORMAT_RGBA_8888: + case COGL_PIXEL_FORMAT_BGRA_8888: + case COGL_PIXEL_FORMAT_ARGB_8888: + case COGL_PIXEL_FORMAT_ABGR_8888: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_BYTE; + required_format = COGL_PIXEL_FORMAT_RGBA_8888; + required_format |= (format & COGL_PREMULT_BIT); + break; + + /* The following three types of channel ordering + * are always defined using system word byte + * ordering (even according to GLES spec) */ + case COGL_PIXEL_FORMAT_RGB_565: + glintformat = GL_RGB; + glformat = GL_RGB; + gltype = GL_UNSIGNED_SHORT_5_6_5; + break; + case COGL_PIXEL_FORMAT_RGBA_4444: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case COGL_PIXEL_FORMAT_RGBA_5551: + glintformat = GL_RGBA; + glformat = GL_RGBA; + gltype = GL_UNSIGNED_SHORT_5_5_5_1; + break; + + /* FIXME: check extensions for YUV support */ + default: + break; + } + + if (out_glintformat != NULL) + *out_glintformat = glintformat; + if (out_glformat != NULL) + *out_glformat = glformat; + if (out_gltype != NULL) + *out_gltype = gltype; + + return required_format; +} + +gboolean +_cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target) +{ + /* Allow 2-dimensional textures only */ + if (gl_target != GL_TEXTURE_2D) + return FALSE; + return TRUE; +} + +void +_cogl_texture_driver_gl_generate_mipmaps (GLenum gl_target) +{ + GE( cogl_wrap_glGenerateMipmap (gl_target) ); +} + +CoglPixelFormat +_cogl_texture_driver_find_best_gl_get_data_format ( + CoglPixelFormat format, + GLenum *closest_gl_format, + GLenum *closest_gl_type) +{ + /* Find closest format that's supported by GL + (Can't use _cogl_pixel_format_to_gl since available formats + when reading pixels on GLES are severely limited) */ + *closest_gl_format = GL_RGBA; + *closest_gl_type = GL_UNSIGNED_BYTE; + return COGL_PIXEL_FORMAT_RGBA_8888; +} + diff --git a/gles/cogl-texture-private.h b/gles/cogl-texture-private.h deleted file mode 100644 index ad74ad121..000000000 --- a/gles/cogl-texture-private.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __COGL_TEXTURE_H -#define __COGL_TEXTURE_H - -#include "cogl-bitmap-private.h" -#include "cogl-material-private.h" -#include "cogl-handle.h" - -typedef struct _CoglTexture CoglTexture; -typedef struct _CoglTexSliceSpan CoglTexSliceSpan; -typedef struct _CoglSpanIter CoglSpanIter; -typedef struct _CoglTexturePixel CoglTexturePixel; - -struct _CoglTexSliceSpan -{ - gint start; - gint size; - gint waste; -}; - -struct _CoglSpanIter -{ - gint index; - GArray *array; - CoglTexSliceSpan *span; - float pos; - float next_pos; - float origin; - float cover_start; - float cover_end; - float intersect_start; - float intersect_end; - float intersect_start_local; - float intersect_end_local; - gboolean intersects; -}; - -/* This is used to store the first pixel of each slice. This is only - used when glGenerateMipmap is not available */ -struct _CoglTexturePixel -{ - /* We need to store the format of the pixel because we store the - data in the source format which might end up being different for - each slice if a subregion is updated with a different format */ - GLenum gl_format; - GLenum gl_type; - guint8 data[4]; -}; - -struct _CoglTexture -{ - CoglHandleObject _parent; - CoglBitmap bitmap; - gboolean bitmap_owner; - GLenum gl_target; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - GArray *slice_x_spans; - GArray *slice_y_spans; - GArray *slice_gl_handles; - gint max_waste; - GLenum min_filter; - GLenum mag_filter; - gboolean is_foreign; - GLint wrap_mode; - gboolean auto_mipmap; - gboolean mipmaps_dirty; - - /* This holds a copy of the first pixel in each slice. It is only - used to force an automatic update of the mipmaps when - glGenerateMipmap is not available. */ - CoglTexturePixel *first_pixels; -}; - -/* To improve batching of geometry when submitting vertices to OpenGL we - * log the texture rectangles we want to draw to a journal, so when we - * later flush the journal we aim to batch data, and gl draw calls. */ -typedef struct _CoglJournalEntry -{ - CoglHandle material; - gint n_layers; - guint32 fallback_mask; - GLuint layer0_override_texture; - CoglMatrix model_view; - CoglMaterialFlushOptions flush_options; -} CoglJournalEntry; - -CoglTexture* -_cogl_texture_pointer_from_handle (CoglHandle handle); - -void -_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, - GLenum wrap_mode); - -void -_cogl_texture_set_filters (CoglHandle handle, - GLenum min_filter, - GLenum mag_filter); - -void -_cogl_texture_ensure_mipmaps (CoglHandle handle); - -gboolean -_cogl_texture_span_has_waste (CoglTexture *tex, - gint x_span_index, - gint y_span_index); - -void -_cogl_span_iter_begin (CoglSpanIter *iter, - GArray *array, - float origin, - float cover_start, - float cover_end); - -gboolean -_cogl_span_iter_end (CoglSpanIter *iter); - -void -_cogl_span_iter_next (CoglSpanIter *iter); - -#endif /* __COGL_TEXTURE_H */ diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c deleted file mode 100644 index 5070b785c..000000000 --- a/gles/cogl-texture.c +++ /dev/null @@ -1,2066 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "cogl.h" -#include "cogl-internal.h" -#include "cogl-util.h" -#include "cogl-bitmap-private.h" -#include "cogl-texture-private.h" -#include "cogl-material.h" -#include "cogl-context.h" -#include "cogl-handle.h" - -#include "cogl-gles2-wrapper.h" - -#include -#include -#include - -extern void _cogl_journal_flush (void); - -static void _cogl_texture_free (CoglTexture *tex); - -COGL_HANDLE_DEFINE (Texture, texture); - -static void -_cogl_texture_bitmap_free (CoglTexture *tex) -{ - if (tex->bitmap.data != NULL && tex->bitmap_owner) - g_free (tex->bitmap.data); - - tex->bitmap.data = NULL; - tex->bitmap_owner = FALSE; -} - -static void -_cogl_texture_bitmap_swap (CoglTexture *tex, - CoglBitmap *new_bitmap) -{ - if (tex->bitmap.data != NULL && tex->bitmap_owner) - g_free (tex->bitmap.data); - - tex->bitmap = *new_bitmap; - tex->bitmap_owner = TRUE; -} - -static void -_cogl_span_iter_update (CoglSpanIter *iter) -{ - /* Pick current span */ - iter->span = &g_array_index (iter->array, - CoglTexSliceSpan, - iter->index); - - /* Offset next position by span size */ - iter->next_pos = iter->pos + - (float)(iter->span->size - iter->span->waste); - - /* Check if span intersects the area to cover */ - if (iter->next_pos <= iter->cover_start || - iter->pos >= iter->cover_end) - { - /* Intersection undefined */ - iter->intersects = FALSE; - return; - } - - iter->intersects = TRUE; - - /* Clip start position to coverage area */ - if (iter->pos < iter->cover_start) - iter->intersect_start = iter->cover_start; - else - iter->intersect_start = iter->pos; - - /* Clip end position to coverage area */ - if (iter->next_pos > iter->cover_end) - iter->intersect_end = iter->cover_end; - else - iter->intersect_end = iter->next_pos; -} - -void -_cogl_span_iter_begin (CoglSpanIter *iter, - GArray *array, - float origin, - float cover_start, - float cover_end) -{ - /* Copy info */ - iter->index = 0; - iter->array = array; - iter->span = NULL; - iter->origin = origin; - iter->cover_start = cover_start; - iter->cover_end = cover_end; - iter->pos = iter->origin; - - /* Update intersection */ - _cogl_span_iter_update (iter); -} - -void -_cogl_span_iter_next (CoglSpanIter *iter) -{ - /* Move current position */ - iter->pos = iter->next_pos; - - /* Pick next slice (wrap when last reached) */ - iter->index = (iter->index + 1) % iter->array->len; - - /* Update intersection */ - _cogl_span_iter_update (iter); -} - -gboolean -_cogl_span_iter_end (CoglSpanIter *iter) -{ - /* End reached when whole area covered */ - return iter->pos >= iter->cover_end; -} - -static void -prep_for_gl_pixels_upload (gint pixels_rowstride, - gint pixels_src_x, - gint pixels_src_y, - gint pixels_bpp) -{ - - if (!(pixels_rowstride & 0x7)) - GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) ); - else if (!(pixels_rowstride & 0x3)) - GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 4) ); - else if (!(pixels_rowstride & 0x1)) - GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 2) ); - else - GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) ); -} - -static void -prep_for_gl_pixels_download (gint pixels_rowstride) -{ - if (!(pixels_rowstride & 0x7)) - GE( glPixelStorei (GL_PACK_ALIGNMENT, 8) ); - else if (!(pixels_rowstride & 0x3)) - GE( glPixelStorei (GL_PACK_ALIGNMENT, 4) ); - else if (!(pixels_rowstride & 0x1)) - GE( glPixelStorei (GL_PACK_ALIGNMENT, 2) ); - else - GE( glPixelStorei (GL_PACK_ALIGNMENT, 1) ); -} - -static guchar * -_cogl_texture_allocate_waste_buffer (CoglTexture *tex) -{ - CoglTexSliceSpan *last_x_span; - CoglTexSliceSpan *last_y_span; - guchar *waste_buf = NULL; - - /* If the texture has any waste then allocate a buffer big enough to - fill the gaps */ - last_x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, - tex->slice_x_spans->len - 1); - last_y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, - tex->slice_y_spans->len - 1); - if (last_x_span->waste > 0 || last_y_span->waste > 0) - { - gint bpp = _cogl_get_format_bpp (tex->bitmap.format); - CoglTexSliceSpan *first_x_span - = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - CoglTexSliceSpan *first_y_span - = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - guint right_size = first_y_span->size * last_x_span->waste; - guint bottom_size = first_x_span->size * last_y_span->waste; - - waste_buf = g_malloc (MAX (right_size, bottom_size) * bpp); - } - - return waste_buf; -} - -static gboolean -_cogl_texture_upload_to_gl (CoglTexture *tex) -{ - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - GLuint gl_handle; - gint bpp; - gint x,y; - guchar *waste_buf; - CoglBitmap slice_bmp; - - bpp = _cogl_get_format_bpp (tex->bitmap.format); - - waste_buf = _cogl_texture_allocate_waste_buffer (tex); - - /* Iterate vertical slices */ - for (y = 0; y < tex->slice_y_spans->len; ++y) - { - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); - - /* Iterate horizontal slices */ - for (x = 0; x < tex->slice_x_spans->len; ++x) - { - gint slice_num = y * tex->slice_x_spans->len + x; - - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); - - /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); - - /* FIXME: might optimize by not copying to intermediate slice - bitmap when source rowstride = bpp * width and the texture - image is not sliced */ - - /* Setup temp bitmap for slice subregion */ - slice_bmp.format = tex->bitmap.format; - slice_bmp.width = x_span->size - x_span->waste; - slice_bmp.height = y_span->size - y_span->waste; - slice_bmp.rowstride = bpp * slice_bmp.width; - slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * - slice_bmp.height); - - /* Setup gl alignment to match rowstride and top-left corner */ - prep_for_gl_pixels_upload (tex->bitmap.rowstride, - 0, - 0, - bpp); - - /* Copy subregion data */ - _cogl_bitmap_copy_subregion (&tex->bitmap, - &slice_bmp, - x_span->start, - y_span->start, - 0, 0, - slice_bmp.width, - slice_bmp.height); - - /* Keep a copy of the first pixel if needed */ - if (tex->first_pixels) - { - memcpy (tex->first_pixels[slice_num].data, - slice_bmp.data, - bpp); - tex->first_pixels[slice_num].gl_format = tex->gl_format; - tex->first_pixels[slice_num].gl_type = tex->gl_type; - } - - /* Upload new image data */ - GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, - tex->gl_intformat) ); - - GE( glTexSubImage2D (tex->gl_target, 0, - 0, - 0, - slice_bmp.width, - slice_bmp.height, - tex->gl_format, tex->gl_type, - slice_bmp.data) ); - - /* Fill the waste with a copies of the rightmost pixels */ - if (x_span->waste > 0) - { - const guchar *src = tex->bitmap.data - + y_span->start * tex->bitmap.rowstride - + (x_span->start + x_span->size - x_span->waste - 1) * bpp; - guchar *dst = waste_buf; - guint wx, wy; - - for (wy = 0; wy < y_span->size - y_span->waste; wy++) - { - for (wx = 0; wx < x_span->waste; wx++) - { - memcpy (dst, src, bpp); - dst += bpp; - } - src += tex->bitmap.rowstride; - } - - prep_for_gl_pixels_upload (x_span->waste * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); - - GE( glTexSubImage2D (tex->gl_target, 0, - x_span->size - x_span->waste, - 0, - x_span->waste, - y_span->size - y_span->waste, - tex->gl_format, tex->gl_type, - waste_buf) ); - } - - if (y_span->waste > 0) - { - const guchar *src = tex->bitmap.data - + ((y_span->start + y_span->size - y_span->waste - 1) - * tex->bitmap.rowstride) - + x_span->start * bpp; - guchar *dst = waste_buf; - guint wy, wx; - - for (wy = 0; wy < y_span->waste; wy++) - { - memcpy (dst, src, (x_span->size - x_span->waste) * bpp); - dst += (x_span->size - x_span->waste) * bpp; - - for (wx = 0; wx < x_span->waste; wx++) - { - memcpy (dst, dst - bpp, bpp); - dst += bpp; - } - } - - prep_for_gl_pixels_upload (x_span->size * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); - - GE( glTexSubImage2D (tex->gl_target, 0, - 0, - y_span->size - y_span->waste, - x_span->size, - y_span->waste, - tex->gl_format, tex->gl_type, - waste_buf) ); - } - - /* Free temp bitmap */ - g_free (slice_bmp.data); - } - } - - if (waste_buf) - g_free (waste_buf); - - tex->mipmaps_dirty = TRUE; - - return TRUE; -} - -static void -_cogl_texture_draw_and_read (CoglTexture *tex, - CoglBitmap *target_bmp, - GLint *viewport) -{ - gint bpp; - float rx1, ry1; - float rx2, ry2; - float tx1, ty1; - float tx2, ty2; - int bw, bh; - CoglBitmap rect_bmp; - CoglHandle handle; - - handle = (CoglHandle) tex; - bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); - - ry1 = 0; ry2 = 0; - ty1 = 0; ty2 = 0; - - /* Walk Y axis until whole bitmap height consumed */ - for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3]) - { - /* Rectangle Y coords */ - ry1 = ry2; - ry2 += (bh < viewport[3]) ? bh : viewport[3]; - - /* Normalized texture Y coords */ - ty1 = ty2; - ty2 = (ry2 / (float)tex->bitmap.height); - - rx1 = 0; rx2 = 0; - tx1 = 0; tx2 = 0; - - /* Walk X axis until whole bitmap width consumed */ - for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2]) - { - /* Rectangle X coords */ - rx1 = rx2; - rx2 += (bw < viewport[2]) ? bw : viewport[2]; - - /* Normalized texture X coords */ - tx1 = tx2; - tx2 = (rx2 / (float)tex->bitmap.width); - - /* Draw a portion of texture */ - cogl_rectangle_with_texture_coords (0, 0, - rx2 - rx1, - ry2 - ry1, - tx1, ty1, - tx2, ty2); - - /* Read into a temporary bitmap */ - rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; - rect_bmp.width = rx2 - rx1; - rect_bmp.height = ry2 - ry1; - rect_bmp.rowstride = bpp * rect_bmp.width; - rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * - rect_bmp.height); - - prep_for_gl_pixels_download (rect_bmp.rowstride); - GE( glReadPixels (viewport[0], viewport[1], - rect_bmp.width, - rect_bmp.height, - GL_RGBA, GL_UNSIGNED_BYTE, - rect_bmp.data) ); - - /* Copy to target bitmap */ - _cogl_bitmap_copy_subregion (&rect_bmp, - target_bmp, - 0,0, - rx1,ry1, - rect_bmp.width, - rect_bmp.height); - - /* Free temp bitmap */ - g_free (rect_bmp.data); - } - } -} - -static gboolean -_cogl_texture_download_from_gl (CoglTexture *tex, - CoglBitmap *target_bmp, - GLuint target_gl_format, - GLuint target_gl_type) -{ - gint bpp; - GLint viewport[4]; - CoglBitmap alpha_bmp; - CoglHandle prev_source; - - _COGL_GET_CONTEXT (ctx, FALSE); - - - bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); - - /* Viewport needs to have some size and be inside the window for this */ - GE( glGetIntegerv (GL_VIEWPORT, viewport) ); - - if (viewport[0] < 0 || viewport[1] < 0 || - viewport[2] <= 0 || viewport[3] <= 0) - return FALSE; - - /* Setup orthographic projection into current viewport - (0,0 in bottom-left corner to draw the texture - upside-down so we match the way glReadPixels works) */ - - _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); - _cogl_current_matrix_push (); - _cogl_current_matrix_identity (); - - _cogl_current_matrix_ortho (0, (float)(viewport[2]), - 0, (float)(viewport[3]), - (float)(0), - (float)(100)); - - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - _cogl_current_matrix_push (); - _cogl_current_matrix_identity (); - - /* Direct copy operation */ - - if (ctx->texture_download_material == COGL_INVALID_HANDLE) - { - ctx->texture_download_material = cogl_material_new (); - cogl_material_set_blend (ctx->texture_download_material, - "RGBA = ADD (SRC_COLOR, 0)", - NULL); - } - - prev_source = cogl_handle_ref (ctx->source_material); - cogl_set_source (ctx->texture_download_material); - - cogl_material_set_layer (ctx->texture_download_material, 0, tex); - - cogl_material_set_layer_combine (ctx->texture_download_material, - 0, /* layer */ - "RGBA = REPLACE (TEXTURE)", - NULL); - - _cogl_texture_draw_and_read (tex, target_bmp, viewport); - - /* Check whether texture has alpha and framebuffer not */ - /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer - still doesn't seem to have an alpha buffer. This might be just - a PowerVR issue. - GLint r_bits, g_bits, b_bits, a_bits; - GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); - GE( glGetIntegerv (GL_RED_BITS, &r_bits) ); - GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) ); - GE( 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 ((tex->bitmap.format & COGL_A_BIT)/* && a_bits == 0*/) - { - guchar *srcdata; - guchar *dstdata; - guchar *srcpixel; - guchar *dstpixel; - gint x,y; - - /* Create temp bitmap for alpha values */ - alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; - alpha_bmp.width = target_bmp->width; - alpha_bmp.height = target_bmp->height; - alpha_bmp.rowstride = bpp * alpha_bmp.width; - alpha_bmp.data = (guchar*) g_malloc (alpha_bmp.rowstride * - alpha_bmp.height); - - /* Draw alpha values into RGB channels */ - cogl_material_set_layer_combine (ctx->texture_download_material, - 0, /* layer */ - "RGBA = REPLACE (TEXTURE[A])", - NULL); - - _cogl_texture_draw_and_read (tex, &alpha_bmp, viewport); - - /* Copy temp R to target A */ - srcdata = alpha_bmp.data; - dstdata = target_bmp->data; - - for (y=0; yheight; ++y) - { - for (x=0; xwidth; ++x) - { - srcpixel = srcdata + x*bpp; - dstpixel = dstdata + x*bpp; - dstpixel[3] = srcpixel[0]; - } - srcdata += alpha_bmp.rowstride; - dstdata += target_bmp->rowstride; - } - - g_free (alpha_bmp.data); - } - - /* Restore old state */ - _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); - _cogl_current_matrix_pop (); - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - _cogl_current_matrix_pop (); - - /* restore the original material */ - cogl_set_source (prev_source); - cogl_handle_unref (prev_source); - - return TRUE; -} - -static gboolean -_cogl_texture_upload_subregion_to_gl (CoglTexture *tex, - gint src_x, - gint src_y, - gint dst_x, - gint dst_y, - gint width, - gint height, - CoglBitmap *source_bmp, - GLuint source_gl_format, - GLuint source_gl_type) -{ - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - gint bpp; - CoglSpanIter x_iter; - CoglSpanIter y_iter; - GLuint gl_handle; - gint source_x = 0, source_y = 0; - gint inter_w = 0, inter_h = 0; - gint local_x = 0, local_y = 0; - guchar *waste_buf; - CoglBitmap slice_bmp; - - bpp = _cogl_get_format_bpp (source_bmp->format); - - waste_buf = _cogl_texture_allocate_waste_buffer (tex); - - /* Iterate vertical spans */ - for (source_y = src_y, - _cogl_span_iter_begin (&y_iter, tex->slice_y_spans, - 0, (float)(dst_y), - (float)(dst_y + height)); - - !_cogl_span_iter_end (&y_iter); - - _cogl_span_iter_next (&y_iter), - source_y += inter_h ) - { - /* Discard slices out of the subregion early */ - if (!y_iter.intersects) - { - inter_h = 0; - continue; - } - - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, - y_iter.index); - - /* Iterate horizontal spans */ - for (source_x = src_x, - _cogl_span_iter_begin (&x_iter, tex->slice_x_spans, - 0, (float)(dst_x), - (float)(dst_x + width)); - - !_cogl_span_iter_end (&x_iter); - - _cogl_span_iter_next (&x_iter), - source_x += inter_w ) - { - gint slice_num; - - /* Discard slices out of the subregion early */ - if (!x_iter.intersects) - { - inter_w = 0; - continue; - } - - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, - x_iter.index); - - /* Pick intersection width and height */ - inter_w = (x_iter.intersect_end - - x_iter.intersect_start); - inter_h = (y_iter.intersect_end - - y_iter.intersect_start); - - /* Localize intersection top-left corner to slice*/ - local_x = (x_iter.intersect_start - - x_iter.pos); - local_y = (y_iter.intersect_start - - y_iter.pos); - - slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; - - /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); - - /* FIXME: might optimize by not copying to intermediate slice - bitmap when source rowstride = bpp * width and the texture - image is not sliced */ - - /* Setup temp bitmap for slice subregion */ - slice_bmp.format = tex->bitmap.format; - slice_bmp.width = inter_w; - slice_bmp.height = inter_h; - slice_bmp.rowstride = bpp * slice_bmp.width; - slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * - slice_bmp.height); - - /* Setup gl alignment to match rowstride and top-left corner */ - prep_for_gl_pixels_upload (slice_bmp.rowstride, - 0, /* src x */ - 0, /* src y */ - bpp); - - /* Copy subregion data */ - _cogl_bitmap_copy_subregion (source_bmp, - &slice_bmp, - source_x, - source_y, - 0, 0, - slice_bmp.width, - slice_bmp.height); - - /* Keep a copy of the first pixel if needed */ - if (tex->first_pixels && local_x == 0 && local_y == 0) - { - memcpy (tex->first_pixels[slice_num].data, - slice_bmp.data, bpp); - tex->first_pixels[slice_num].gl_format = source_gl_format; - tex->first_pixels[slice_num].gl_type = source_gl_type; - } - - /* Upload new image data */ - GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, - tex->gl_intformat) ); - - GE( glTexSubImage2D (tex->gl_target, 0, - local_x, local_y, - inter_w, inter_h, - source_gl_format, - source_gl_type, - slice_bmp.data) ); - - /* If the x_span is sliced and the upload touches the - rightmost pixels then fill the waste with copies of the - pixels */ - if (x_span->waste > 0 - && local_x < x_span->size - x_span->waste - && local_x + inter_w >= x_span->size - x_span->waste) - { - const guchar *src; - guchar *dst; - guint wx, wy; - - src = source_bmp->data - + (src_y + ((int)y_iter.intersect_start) - - dst_y) - * source_bmp->rowstride - + (src_x + x_span->start + x_span->size - x_span->waste - - dst_x - 1) - * bpp; - - dst = waste_buf; - - for (wy = 0; wy < inter_h; wy++) - { - for (wx = 0; wx < x_span->waste; wx++) - { - memcpy (dst, src, bpp); - dst += bpp; - } - src += source_bmp->rowstride; - } - - prep_for_gl_pixels_upload (x_span->waste * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); - - GE( glTexSubImage2D (tex->gl_target, 0, - x_span->size - x_span->waste, - local_y, - x_span->waste, - inter_h, - source_gl_format, - source_gl_type, - waste_buf) ); - } - - /* same for the bottom-most pixels */ - if (y_span->waste > 0 - && local_y < y_span->size - y_span->waste - && local_y + inter_h >= y_span->size - y_span->waste) - { - const guchar *src; - guchar *dst; - guint wy, wx; - guint copy_width; - - src = source_bmp->data - + (src_x + ((int)x_iter.intersect_start) - - dst_x) - * bpp - + (src_y + y_span->start + y_span->size - y_span->waste - - dst_y - 1) - * source_bmp->rowstride; - - dst = waste_buf; - - if (local_x + inter_w >= x_span->size - x_span->waste) - copy_width = x_span->size - local_x; - else - copy_width = inter_w; - - for (wy = 0; wy < y_span->waste; wy++) - { - memcpy (dst, src, inter_w * bpp); - dst += inter_w * bpp; - - for (wx = inter_w; wx < copy_width; wx++) - { - memcpy (dst, dst - bpp, bpp); - dst += bpp; - } - } - - prep_for_gl_pixels_upload (copy_width * bpp, - 0, /* src x */ - 0, /* src y */ - bpp); - - GE( glTexSubImage2D (tex->gl_target, 0, - local_x, - y_span->size - y_span->waste, - copy_width, - y_span->waste, - source_gl_format, - source_gl_type, - waste_buf) ); - } - - /* Free temp bitmap */ - g_free (slice_bmp.data); - } - } - - if (waste_buf) - g_free (waste_buf); - - tex->mipmaps_dirty = TRUE; - - return TRUE; -} - -static gint -_cogl_rect_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) -{ - gint n_spans = 0; - CoglTexSliceSpan span; - - /* Init first slice span */ - span.start = 0; - span.size = max_span_size; - span.waste = 0; - - /* Repeat until whole area covered */ - while (size_to_fill >= span.size) - { - /* Add another slice span of same size */ - if (out_spans) g_array_append_val (out_spans, span); - span.start += span.size; - size_to_fill -= span.size; - n_spans++; - } - - /* Add one last smaller slice span */ - if (size_to_fill > 0) - { - span.size = size_to_fill; - if (out_spans) g_array_append_val (out_spans, span); - n_spans++; - } - - return n_spans; -} - -static gint -_cogl_pot_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) -{ - gint n_spans = 0; - CoglTexSliceSpan span; - - /* Init first slice span */ - span.start = 0; - span.size = max_span_size; - span.waste = 0; - - /* Fix invalid max_waste */ - if (max_waste < 0) - max_waste = 0; - - while (TRUE) - { - /* Is the whole area covered? */ - if (size_to_fill > span.size) - { - /* Not yet - add a span of this size */ - if (out_spans) - g_array_append_val (out_spans, span); - - span.start += span.size; - size_to_fill -= span.size; - n_spans++; - } - else if (span.size - size_to_fill <= max_waste) - { - /* Yes and waste is small enough */ - span.waste = span.size - size_to_fill; - if (out_spans) - g_array_append_val (out_spans, span); - - return ++n_spans; - } - else - { - /* Yes but waste is too large */ - while (span.size - size_to_fill > max_waste) - { - span.size /= 2; - g_assert (span.size > 0); - } - } - } - - /* Can't get here */ - return 0; -} - -static gboolean -_cogl_texture_size_supported (GLenum gl_target, - GLenum gl_format, - GLenum gl_type, - int width, - int height) -{ - return TRUE; -} - -void -_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, - GLenum wrap_mode) -{ - /* Only set the wrap mode if it's different from the current - value to avoid too many GL calls */ - if (tex->wrap_mode != wrap_mode) - { - int i; - - /* Any queued texture rectangles may be depending on the previous - * wrap mode... */ - _cogl_journal_flush (); - - for (i = 0; i < tex->slice_gl_handles->len; i++) - { - GLuint texnum = g_array_index (tex->slice_gl_handles, GLuint, i); - - GE( glBindTexture (tex->gl_target, texnum) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, wrap_mode) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, wrap_mode) ); - } - - tex->wrap_mode = wrap_mode; - } -} - -static gboolean -_cogl_texture_slices_create (CoglTexture *tex) -{ - gint bpp; - gint max_width; - gint max_height; - GLuint *gl_handles; - gint n_x_slices; - gint n_y_slices; - gint n_slices; - gint x, y; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - - gint (*slices_for_size) (gint, gint, gint, GArray*); - - bpp = _cogl_get_format_bpp (tex->bitmap.format); - - /* Initialize size of largest slice according to supported features */ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)) - { - max_width = tex->bitmap.width; - max_height = tex->bitmap.height; - tex->gl_target = GL_TEXTURE_2D; - slices_for_size = _cogl_rect_slices_for_size; - } - else - { - max_width = cogl_util_next_p2 (tex->bitmap.width); - max_height = cogl_util_next_p2 (tex->bitmap.height); - tex->gl_target = GL_TEXTURE_2D; - slices_for_size = _cogl_pot_slices_for_size; - } - - /* Negative number means no slicing forced by the user */ - if (tex->max_waste <= -1) - { - CoglTexSliceSpan span; - - /* Check if size supported else bail out */ - if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) - { - return FALSE; - } - - n_x_slices = 1; - n_y_slices = 1; - - /* Init span arrays */ - tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), - 1); - - tex->slice_y_spans = g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), - 1); - - /* Add a single span for width and height */ - span.start = 0; - span.size = max_width; - span.waste = max_width - tex->bitmap.width; - g_array_append_val (tex->slice_x_spans, span); - - span.size = max_height; - span.waste = max_height - tex->bitmap.height; - g_array_append_val (tex->slice_y_spans, span); - } - else - { - /* Decrease the size of largest slice until supported by GL */ - while (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) - { - /* Alternate between width and height */ - if (max_width > max_height) - max_width /= 2; - else - max_height /= 2; - - if (max_width == 0 || max_height == 0) - return FALSE; - } - - /* Determine the slices required to cover the bitmap area */ - n_x_slices = slices_for_size (tex->bitmap.width, - max_width, tex->max_waste, - NULL); - - n_y_slices = slices_for_size (tex->bitmap.height, - max_height, tex->max_waste, - NULL); - - /* Init span arrays with reserved size */ - tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), - n_x_slices); - - tex->slice_y_spans = g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), - n_y_slices); - - /* Fill span arrays with info */ - slices_for_size (tex->bitmap.width, - max_width, tex->max_waste, - tex->slice_x_spans); - - slices_for_size (tex->bitmap.height, - max_height, tex->max_waste, - tex->slice_y_spans); - } - - /* Init and resize GL handle array */ - n_slices = n_x_slices * n_y_slices; - - tex->slice_gl_handles = g_array_sized_new (FALSE, FALSE, - sizeof (GLuint), - n_slices); - - g_array_set_size (tex->slice_gl_handles, n_slices); - - /* Allocate some space to store a copy of the first pixel of each - slice. This is only needed to glGenerateMipmap (which is part of - the FBO extension) is not available */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) - tex->first_pixels = NULL; - else - tex->first_pixels = g_new (CoglTexturePixel, n_slices); - - /* Wrap mode not yet set */ - tex->wrap_mode = GL_FALSE; - - /* Generate a "working set" of GL texture objects - * (some implementations might supported faster - * re-binding between textures inside a set) */ - gl_handles = (GLuint*) tex->slice_gl_handles->data; - - GE( glGenTextures (n_slices, gl_handles) ); - - - /* Init each GL texture object */ - for (y = 0; y < n_y_slices; ++y) - { - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); - - for (x = 0; x < n_x_slices; ++x) - { - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); - -#if COGL_DEBUG - printf ("CREATE SLICE (%d,%d)\n", x,y); - printf ("size: (%d x %d)\n", - x_span->size - x_span->waste, - y_span->size - y_span->waste); -#endif - /* Setup texture parameters */ - GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, - gl_handles[y * n_x_slices + x], - tex->gl_intformat) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, - tex->wrap_mode) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, - tex->wrap_mode) ); - - /* Pass NULL data to init size and internal format */ - GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, - x_span->size, y_span->size, 0, - tex->gl_format, tex->gl_type, 0) ); - } - } - - return TRUE; -} - -static void -_cogl_texture_slices_free (CoglTexture *tex) -{ - if (tex->slice_x_spans != NULL) - g_array_free (tex->slice_x_spans, TRUE); - - if (tex->slice_y_spans != NULL) - g_array_free (tex->slice_y_spans, TRUE); - - if (tex->slice_gl_handles != NULL) - { - if (tex->is_foreign == FALSE) - { - GE( glDeleteTextures (tex->slice_gl_handles->len, - (GLuint*) tex->slice_gl_handles->data) ); - } - - g_array_free (tex->slice_gl_handles, TRUE); - } - - if (tex->first_pixels != NULL) - g_free (tex->first_pixels); -} - -gboolean -_cogl_texture_span_has_waste (CoglTexture *tex, - gint x_span_index, - gint y_span_index) -{ - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x_span_index); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y_span_index); - - return (x_span->waste || y_span->waste) ? TRUE : FALSE; -} - -static gboolean -_cogl_pixel_format_from_gl_internal (GLenum gl_int_format, - CoglPixelFormat *out_format) -{ - return TRUE; -} - -static CoglPixelFormat -_cogl_pixel_format_to_gl (CoglPixelFormat format, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype) -{ - CoglPixelFormat required_format; - GLenum glintformat = 0; - GLenum glformat = 0; - GLenum gltype = 0; - - /* FIXME: check YUV support */ - - required_format = format; - - /* Find GL equivalents */ - switch (format & COGL_UNPREMULT_MASK) - { - case COGL_PIXEL_FORMAT_A_8: - glintformat = GL_ALPHA; - glformat = GL_ALPHA; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_G_8: - glintformat = GL_LUMINANCE; - glformat = GL_LUMINANCE; - gltype = GL_UNSIGNED_BYTE; - break; - - /* Just one 24-bit ordering supported */ - case COGL_PIXEL_FORMAT_RGB_888: - case COGL_PIXEL_FORMAT_BGR_888: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_BYTE; - required_format = COGL_PIXEL_FORMAT_RGB_888; - break; - - /* Just one 32-bit ordering supported */ - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ABGR_8888: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_BYTE; - required_format = COGL_PIXEL_FORMAT_RGBA_8888; - required_format |= (format & COGL_PREMULT_BIT); - break; - - /* The following three types of channel ordering - * are always defined using system word byte - * ordering (even according to GLES spec) */ - case COGL_PIXEL_FORMAT_RGB_565: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - case COGL_PIXEL_FORMAT_RGBA_4444: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case COGL_PIXEL_FORMAT_RGBA_5551: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_5_5_5_1; - break; - - /* FIXME: check extensions for YUV support */ - default: - break; - } - - if (out_glintformat != NULL) - *out_glintformat = glintformat; - if (out_glformat != NULL) - *out_glformat = glformat; - if (out_gltype != NULL) - *out_gltype = gltype; - - return required_format; -} - -static gboolean -_cogl_texture_bitmap_prepare (CoglTexture *tex, - CoglPixelFormat internal_format) -{ - CoglBitmap new_bitmap; - CoglPixelFormat new_data_format; - gboolean success; - - /* Was there any internal conversion requested? - * By default Cogl will use a premultiplied internal format. Later we will - * add control over this. */ - if (internal_format == COGL_PIXEL_FORMAT_ANY) - { - if ((tex->bitmap.format & COGL_A_BIT) && - tex->bitmap.format != COGL_PIXEL_FORMAT_A_8) - internal_format = tex->bitmap.format | COGL_PREMULT_BIT; - else - internal_format = tex->bitmap.format; - } - - /* Find closest format accepted by GL */ - new_data_format = _cogl_pixel_format_to_gl (internal_format, - &tex->gl_intformat, - &tex->gl_format, - &tex->gl_type); - - /* Convert to internal format */ - if (new_data_format != tex->bitmap.format) - { - success = _cogl_bitmap_convert_and_premult (&tex->bitmap, - &new_bitmap, - new_data_format); - - if (!success) - return FALSE; - - /* Update texture with new data */ - _cogl_texture_bitmap_swap (tex, &new_bitmap); - } - - return TRUE; -} - -static void -_cogl_texture_free (CoglTexture *tex) -{ - /* Frees texture resources but its handle is not - released! Do that separately before this! */ - _cogl_texture_bitmap_free (tex); - _cogl_texture_slices_free (tex); - g_free (tex); -} - -CoglHandle -cogl_texture_new_with_size (guint width, - guint height, - CoglTextureFlags flags, - CoglPixelFormat internal_format) -{ - CoglTexture *tex; - gint bpp; - gint rowstride; - - /* Since no data, we need some internal format */ - if (internal_format == COGL_PIXEL_FORMAT_ANY) - return COGL_INVALID_HANDLE; - - /* Rowstride from width */ - bpp = _cogl_get_format_bpp (internal_format); - rowstride = width * bpp; - - /* Init texture with empty bitmap */ - tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); - - tex->is_foreign = FALSE; - tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; - tex->mipmaps_dirty = TRUE; - tex->first_pixels = NULL; - - tex->bitmap.width = width; - tex->bitmap.height = height; - tex->bitmap.format = internal_format; - tex->bitmap.rowstride = rowstride; - tex->bitmap.data = NULL; - tex->bitmap_owner = FALSE; - - tex->slice_x_spans = NULL; - tex->slice_y_spans = NULL; - tex->slice_gl_handles = NULL; - - if (flags & COGL_TEXTURE_NO_SLICING) - tex->max_waste = -1; - else - tex->max_waste = COGL_TEXTURE_MAX_WASTE; - - /* Unknown filter */ - tex->min_filter = GL_FALSE; - tex->mag_filter = GL_FALSE; - - /* Find closest GL format match */ - tex->bitmap.format = - _cogl_pixel_format_to_gl (internal_format, - &tex->gl_intformat, - &tex->gl_format, - &tex->gl_type); - - /* Create slices for the given format and size */ - if (!_cogl_texture_slices_create (tex)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - return _cogl_texture_handle_new (tex); -} - -CoglHandle -cogl_texture_new_from_data (guint width, - guint height, - CoglTextureFlags flags, - CoglPixelFormat format, - CoglPixelFormat internal_format, - guint rowstride, - const guchar *data) -{ - CoglTexture *tex; - gint bpp; - - if (format == COGL_PIXEL_FORMAT_ANY) - return COGL_INVALID_HANDLE; - - if (data == NULL) - return COGL_INVALID_HANDLE; - - /* Rowstride from width if not given */ - bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) rowstride = width * bpp; - - /* Create new texture and fill with given data */ - tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); - - tex->is_foreign = FALSE; - tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; - tex->mipmaps_dirty = TRUE; - tex->first_pixels = NULL; - - tex->bitmap.width = width; - tex->bitmap.height = height; - tex->bitmap.data = (guchar*)data; - tex->bitmap.format = format; - tex->bitmap.rowstride = rowstride; - tex->bitmap_owner = FALSE; - - tex->slice_x_spans = NULL; - tex->slice_y_spans = NULL; - tex->slice_gl_handles = NULL; - - if (flags & COGL_TEXTURE_NO_SLICING) - tex->max_waste = -1; - else - tex->max_waste = COGL_TEXTURE_MAX_WASTE; - - /* Unknown filter */ - tex->min_filter = GL_FALSE; - tex->mag_filter = GL_FALSE; - - /* FIXME: If upload fails we should set some kind of - * error flag but still return texture handle (this - * is to keep the behavior equal to _new_from_file; - * see below) */ - - if (!_cogl_texture_bitmap_prepare (tex, internal_format)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - if (!_cogl_texture_slices_create (tex)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - if (!_cogl_texture_upload_to_gl (tex)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - _cogl_texture_bitmap_free (tex); - - return _cogl_texture_handle_new (tex); -} - -CoglHandle -cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - CoglTextureFlags flags, - CoglPixelFormat internal_format) -{ - CoglTexture *tex; - CoglBitmap *bmp = (CoglBitmap *)bmp_handle; - - /* Create new texture and fill with loaded data */ - tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); - - tex->is_foreign = FALSE; - tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; - tex->mipmaps_dirty = TRUE; - tex->first_pixels = NULL; - - tex->bitmap = *bmp; - tex->bitmap_owner = TRUE; - bmp->data = NULL; - - tex->slice_x_spans = NULL; - tex->slice_y_spans = NULL; - tex->slice_gl_handles = NULL; - - if (flags & COGL_TEXTURE_NO_SLICING) - tex->max_waste = -1; - else - tex->max_waste = COGL_TEXTURE_MAX_WASTE; - - /* Unknown filter */ - tex->min_filter = GL_FALSE; - tex->mag_filter = GL_FALSE; - - /* FIXME: If upload fails we should set some kind of - * error flag but still return texture handle if the - * user decides to destroy another texture and upload - * this one instead (reloading from file is not needed - * in that case). As a rule then, everytime a valid - * CoglHandle is returned, it should also be destroyed - * with cogl_handle_unref at some point! */ - - if (!_cogl_texture_bitmap_prepare (tex, internal_format)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - if (!_cogl_texture_slices_create (tex)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - if (!_cogl_texture_upload_to_gl (tex)) - { - _cogl_texture_free (tex); - return COGL_INVALID_HANDLE; - } - - _cogl_texture_bitmap_free (tex); - - return _cogl_texture_handle_new (tex); -} - -CoglHandle -cogl_texture_new_from_file (const gchar *filename, - CoglTextureFlags flags, - CoglPixelFormat internal_format, - GError **error) -{ - CoglHandle bmp; - CoglHandle handle; - - g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE); - - bmp = cogl_bitmap_new_from_file (filename, error); - if (bmp == COGL_INVALID_HANDLE) - return COGL_INVALID_HANDLE; - - handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format); - cogl_handle_unref (bmp); - - return handle; -} - -CoglHandle -cogl_texture_new_from_foreign (GLuint gl_handle, - GLenum gl_target, - GLuint width, - GLuint height, - GLuint x_pot_waste, - GLuint y_pot_waste, - CoglPixelFormat format) -{ - /* NOTE: width, height and internal format are not queriable - in GLES, hence such a function prototype. However, for - OpenGL they are still queried from the texture for improved - robustness and for completeness in case one day GLES gains - support for them. - */ - - GLenum gl_error = 0; - GLboolean gl_istexture; - GLint gl_compressed = GL_FALSE; - GLint gl_int_format = 0; - GLint gl_width = 0; - GLint gl_height = 0; - GLint gl_gen_mipmap; - guint bpp; - CoglTexture *tex; - CoglTexSliceSpan x_span; - CoglTexSliceSpan y_span; - - /* Allow 2-dimensional textures only */ - if (gl_target != GL_TEXTURE_2D) - return COGL_INVALID_HANDLE; - - /* Make sure it is a valid GL texture object */ - gl_istexture = glIsTexture (gl_handle); - if (gl_istexture == GL_FALSE) - return COGL_INVALID_HANDLE; - - /* Make sure binding succeeds */ - gl_error = glGetError (); - glBindTexture (gl_target, gl_handle); - if (glGetError () != GL_NO_ERROR) - return COGL_INVALID_HANDLE; - - /* Obtain texture parameters - (only level 0 we are interested in) */ - -#if HAVE_COGL_GL - GE( glGetTexLevelParameteriv (gl_target, 0, - GL_TEXTURE_COMPRESSED, - &gl_compressed) ); - - GE( glGetTexLevelParameteriv (gl_target, 0, - GL_TEXTURE_INTERNAL_FORMAT, - &gl_int_format) ); - - - GE( glGetTexLevelParameteriv (gl_target, 0, - GL_TEXTURE_WIDTH, - &gl_width) ); - - GE( glGetTexLevelParameteriv (gl_target, 0, - GL_TEXTURE_HEIGHT, - &gl_height) ); -#else - gl_width = width + x_pot_waste; - gl_height = height + y_pot_waste; -#endif - - GE( glGetTexParameteriv (gl_target, - GL_GENERATE_MIPMAP, - &gl_gen_mipmap) ); - - /* Validate width and height */ - if (gl_width <= 0 || gl_height <= 0) - return COGL_INVALID_HANDLE; - - /* Validate pot waste */ - if (x_pot_waste < 0 || x_pot_waste >= gl_width || - y_pot_waste < 0 || y_pot_waste >= gl_height) - return COGL_INVALID_HANDLE; - - /* Compressed texture images not supported */ - if (gl_compressed == GL_TRUE) - return COGL_INVALID_HANDLE; - - /* Try and match to a cogl format */ - if (!_cogl_pixel_format_from_gl_internal (gl_int_format, - &format)) - { - return COGL_INVALID_HANDLE; - } - - /* Create new texture */ - tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); - - /* Setup bitmap info */ - tex->is_foreign = TRUE; - tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; - tex->mipmaps_dirty = TRUE; - tex->first_pixels = NULL; - - bpp = _cogl_get_format_bpp (format); - tex->bitmap.format = format; - tex->bitmap.width = gl_width - x_pot_waste; - tex->bitmap.height = gl_height - y_pot_waste; - tex->bitmap.rowstride = tex->bitmap.width * bpp; - tex->bitmap_owner = FALSE; - - tex->gl_target = gl_target; - tex->gl_intformat = gl_int_format; - tex->gl_format = gl_int_format; - tex->gl_type = GL_UNSIGNED_BYTE; - - /* Unknown filter */ - tex->min_filter = GL_FALSE; - tex->mag_filter = GL_FALSE; - tex->max_waste = 0; - - /* Wrap mode not yet set */ - tex->wrap_mode = GL_FALSE; - - /* Create slice arrays */ - tex->slice_x_spans = - g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), 1); - - tex->slice_y_spans = - g_array_sized_new (FALSE, FALSE, - sizeof (CoglTexSliceSpan), 1); - - tex->slice_gl_handles = - g_array_sized_new (FALSE, FALSE, - sizeof (GLuint), 1); - - /* Store info for a single slice */ - x_span.start = 0; - x_span.size = gl_width; - x_span.waste = x_pot_waste; - g_array_append_val (tex->slice_x_spans, x_span); - - y_span.start = 0; - y_span.size = gl_height; - y_span.waste = y_pot_waste; - g_array_append_val (tex->slice_y_spans, y_span); - - g_array_append_val (tex->slice_gl_handles, gl_handle); - - tex->first_pixels = NULL; - - return _cogl_texture_handle_new (tex); -} - -guint -cogl_texture_get_width (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->bitmap.width; -} - -guint -cogl_texture_get_height (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->bitmap.height; -} - -CoglPixelFormat -cogl_texture_get_format (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return COGL_PIXEL_FORMAT_ANY; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->bitmap.format; -} - -guint -cogl_texture_get_rowstride (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->bitmap.rowstride; -} - -gint -cogl_texture_get_max_waste (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->max_waste; -} - -gboolean -cogl_texture_is_sliced (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return FALSE; - - tex = _cogl_texture_pointer_from_handle (handle); - - if (tex->slice_gl_handles == NULL) - return FALSE; - - if (tex->slice_gl_handles->len <= 1) - return FALSE; - - return TRUE; -} - -gboolean -cogl_texture_get_gl_texture (CoglHandle handle, - GLuint *out_gl_handle, - GLenum *out_gl_target) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return FALSE; - - tex = _cogl_texture_pointer_from_handle (handle); - - if (tex->slice_gl_handles == NULL) - return FALSE; - - if (tex->slice_gl_handles->len < 1) - return FALSE; - - if (out_gl_handle != NULL) - *out_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); - - if (out_gl_target != NULL) - *out_gl_target = tex->gl_target; - - return TRUE; -} - -void -_cogl_texture_set_filters (CoglHandle handle, - GLenum min_filter, - GLenum mag_filter) -{ - CoglTexture *tex; - GLuint gl_handle; - int i; - - if (!cogl_is_texture (handle)) - return; - - tex = _cogl_texture_pointer_from_handle (handle); - - /* Make sure slices were created */ - if (tex->slice_gl_handles == NULL) - return; - - if (min_filter == tex->min_filter - && mag_filter == tex->mag_filter) - return; - - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - - /* Apply new filters to every slice */ - for (i=0; islice_gl_handles->len; ++i) - { - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); - GE( glBindTexture (tex->gl_target, gl_handle) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - } -} - -void -_cogl_texture_ensure_mipmaps (CoglHandle handle) -{ - CoglTexture *tex; - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (!cogl_is_texture (handle)) - return; - - tex = _cogl_texture_pointer_from_handle (handle); - - /* Only update if the mipmaps are dirty */ - if (!tex->auto_mipmap || !tex->mipmaps_dirty) - return; - - /* Make sure slices were created */ - if (tex->slice_gl_handles == NULL) - return; - - /* Regenerate the mipmaps on every slice */ - for (i = 0; i < tex->slice_gl_handles->len; i++) - { - GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); - GE( glBindTexture (tex->gl_target, gl_handle) ); - - /* glGenerateMipmap is defined in the FBO extension */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) - GE( cogl_wrap_glGenerateMipmap (tex->gl_target) ); - else if (tex->first_pixels) - { - CoglTexturePixel *pixel = tex->first_pixels + i; - /* Temporarily enable automatic mipmap generation and - re-upload the first pixel to cause a regeneration */ - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); - GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, - pixel->gl_format, pixel->gl_type, - pixel->data) ); - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); - } - } - - tex->mipmaps_dirty = FALSE; -} - -gboolean -cogl_texture_set_region (CoglHandle handle, - gint src_x, - gint src_y, - gint dst_x, - gint dst_y, - guint dst_width, - guint dst_height, - gint width, - gint height, - CoglPixelFormat format, - guint rowstride, - const guchar *data) -{ - CoglTexture *tex; - gint bpp; - CoglBitmap source_bmp; - CoglBitmap temp_bmp; - gboolean source_bmp_owner = FALSE; - CoglPixelFormat closest_format; - GLenum closest_gl_format; - GLenum closest_gl_type; - gboolean success; - - /* Check if valid texture handle */ - if (!cogl_is_texture (handle)) - return FALSE; - - tex = _cogl_texture_pointer_from_handle (handle); - - /* Check for valid format */ - if (format == COGL_PIXEL_FORMAT_ANY) - return FALSE; - - /* Shortcut out early if the image is empty */ - if (width == 0 || height == 0) - return TRUE; - - /* Init source bitmap */ - source_bmp.width = width; - source_bmp.height = height; - source_bmp.format = format; - source_bmp.data = (guchar*)data; - - /* Rowstride from width if none specified */ - bpp = _cogl_get_format_bpp (format); - source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; - - /* Find closest format to internal that's supported by GL */ - closest_format = _cogl_pixel_format_to_gl (tex->bitmap.format, - NULL, /* don't need */ - &closest_gl_format, - &closest_gl_type); - - /* If no direct match, convert */ - if (closest_format != format) - { - /* Convert to required format */ - success = _cogl_bitmap_convert_and_premult (&source_bmp, - &temp_bmp, - closest_format); - - /* Swap bitmaps if succeeded */ - if (!success) return FALSE; - source_bmp = temp_bmp; - source_bmp_owner = TRUE; - } - - /* Send data to GL */ - _cogl_texture_upload_subregion_to_gl (tex, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - &source_bmp, - closest_gl_format, - closest_gl_type); - - /* Free data if owner */ - if (source_bmp_owner) - g_free (source_bmp.data); - - return TRUE; -} - -gint -cogl_texture_get_data (CoglHandle handle, - CoglPixelFormat format, - guint rowstride, - guchar *data) -{ - CoglTexture *tex; - gint bpp; - gint byte_size; - CoglPixelFormat closest_format; - gint closest_bpp; - GLenum closest_gl_format; - GLenum closest_gl_type; - CoglBitmap target_bmp; - CoglBitmap new_bmp; - gboolean success; - guchar *src; - guchar *dst; - gint y; - - /* Check if valid texture handle */ - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - /* Default to internal format if none specified */ - if (format == COGL_PIXEL_FORMAT_ANY) - format = tex->bitmap.format; - - /* Rowstride from texture width if none specified */ - bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) rowstride = tex->bitmap.width * bpp; - - /* Return byte size if only that requested */ - byte_size = tex->bitmap.height * rowstride; - if (data == NULL) return byte_size; - - /* Find closest format that's supported by GL - (Can't use _cogl_pixel_format_to_gl since available formats - when reading pixels on GLES are severely limited) */ - closest_format = COGL_PIXEL_FORMAT_RGBA_8888; - closest_gl_format = GL_RGBA; - closest_gl_type = GL_UNSIGNED_BYTE; - closest_bpp = _cogl_get_format_bpp (closest_format); - - /* Is the requested format supported? */ - if (closest_format == format) - { - /* Target user data directly */ - target_bmp = tex->bitmap; - target_bmp.format = format; - target_bmp.rowstride = rowstride; - target_bmp.data = data; - } - else - { - /* Target intermediate buffer */ - target_bmp = tex->bitmap; - target_bmp.format = closest_format; - target_bmp.rowstride = target_bmp.width * closest_bpp; - target_bmp.data = (guchar*) g_malloc (target_bmp.height - * target_bmp.rowstride); - } - - /* Retrieve data from slices */ - _cogl_texture_download_from_gl (tex, &target_bmp, - closest_gl_format, - closest_gl_type); - - /* Was intermediate used? */ - if (closest_format != format) - { - /* Convert to requested format */ - success = _cogl_bitmap_convert_and_premult (&target_bmp, - &new_bmp, - format); - - /* Free intermediate data and return if failed */ - g_free (target_bmp.data); - if (!success) return 0; - - /* Copy to user buffer */ - for (y = 0; y < new_bmp.height; ++y) - { - src = new_bmp.data + y * new_bmp.rowstride; - dst = data + y * rowstride; - memcpy (dst, src, new_bmp.width); - } - - /* Free converted data */ - g_free (new_bmp.data); - } - - return byte_size; -} -