A comparison of gl/cogl-texture.c and gles/cogl-texture.c, to reduce

differences and improve maintainability.

	* clutter/cogl/gl/cogl-context.h:
	Adds a CoglTextureGLVertex typedef + texture_vertices and
	texture_vertices_size members to CoglContext for using vertex arrays
	like GLES does

	* clutter/cogl/gl/cogl-context.c:
	Initializes texture_vertices + texture_vertices_size members

	* clutter/cogl/gl/cogl-internal.h:
	Adds COGL_ENABLE_COLOR_ARRAY

	* clutter/cogl/gl/cogl.c:
	Add COGL_ENABLE_COLOR_ARRAY support to cogl_enable

	* clutter/cogl/gles/cogl-context.h:
	Change the CoglTextureGLVertex to use GLfloat for the position
	and texture coord attributes and GLubyte for the color.

	* clutter/cogl/gles/cogl-texture-private.h:
	Adds a wrap_mode member like GL has.

	* clutter/cogl/gl/cogl-texture.c
	* clutter/cogl/gles/cogl-texture.c:
	Improves the comparability of the files, such that the remaining
	differences, better reflect the fundamental differences needed
	between GL and GLES. Notably GL no longer uses glBegin/glEnd for
	submitting vertices, it uses vertex arrays like GLES and this gives
	a small but measurable fps improvement for test-text.
This commit is contained in:
Robert Bragg 2008-11-18 16:24:09 +00:00
parent 6731dfa468
commit 8b557c6c13
8 changed files with 624 additions and 406 deletions

View File

@ -57,6 +57,8 @@ cogl_create_context ()
_context->path_nodes_size = 0; _context->path_nodes_size = 0;
_context->texture_handles = NULL; _context->texture_handles = NULL;
_context->texture_vertices_size = 0;
_context->texture_vertices = NULL;
_context->fbo_handles = NULL; _context->fbo_handles = NULL;
_context->draw_buffer = COGL_WINDOW_BUFFER; _context->draw_buffer = COGL_WINDOW_BUFFER;

View File

@ -28,6 +28,13 @@
#include "cogl-primitives.h" #include "cogl-primitives.h"
typedef struct
{
GLfloat v[3];
GLfloat t[2];
GLubyte c[4];
} CoglTextureGLVertex;
typedef struct typedef struct
{ {
/* Features cache */ /* Features cache */
@ -56,7 +63,9 @@ typedef struct
GLfloat inverse_projection[16]; GLfloat inverse_projection[16];
/* Textures */ /* Textures */
GArray *texture_handles; GArray *texture_handles;
CoglTextureGLVertex *texture_vertices;
gulong texture_vertices_size;
/* Framebuffer objects */ /* Framebuffer objects */
GArray *fbo_handles; GArray *fbo_handles;

View File

@ -56,7 +56,8 @@ const char *_cogl_error_string(GLenum errorCode);
#define COGL_ENABLE_TEXTURE_RECT (1<<4) #define COGL_ENABLE_TEXTURE_RECT (1<<4)
#define COGL_ENABLE_VERTEX_ARRAY (1<<5) #define COGL_ENABLE_VERTEX_ARRAY (1<<5)
#define COGL_ENABLE_TEXCOORD_ARRAY (1<<6) #define COGL_ENABLE_TEXCOORD_ARRAY (1<<6)
#define COGL_ENABLE_BACKFACE_CULLING (1<<7) #define COGL_ENABLE_COLOR_ARRAY (1<<7)
#define COGL_ENABLE_BACKFACE_CULLING (1<<8)
gint gint
_cogl_get_format_bpp (CoglPixelFormat format); _cogl_get_format_bpp (CoglPixelFormat format);

View File

@ -49,10 +49,6 @@
printf("err: 0x%x\n", err); \ printf("err: 0x%x\n", err); \
} */ } */
static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture, texture_handles);
struct _CoglSpanIter struct _CoglSpanIter
{ {
gint index; gint index;
@ -70,6 +66,11 @@ struct _CoglSpanIter
gboolean intersects; gboolean intersects;
}; };
static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture, texture_handles);
static void static void
_cogl_texture_bitmap_free (CoglTexture *tex) _cogl_texture_bitmap_free (CoglTexture *tex)
{ {
@ -100,8 +101,8 @@ _cogl_span_iter_update (CoglSpanIter *iter)
iter->index); iter->index);
/* Offset next position by span size */ /* Offset next position by span size */
iter->next_pos = iter->pos iter->next_pos = iter->pos +
+ COGL_FIXED_FROM_INT (iter->span->size - iter->span->waste); COGL_FIXED_FROM_INT (iter->span->size - iter->span->waste);
/* Check if span intersects the area to cover */ /* Check if span intersects the area to cover */
if (iter->next_pos <= iter->cover_start || if (iter->next_pos <= iter->cover_start ||
@ -168,48 +169,37 @@ _cogl_span_iter_end (CoglSpanIter *iter)
} }
static void static void
_cogl_subregion_gl_store_rules (gint bmp_rowstride, prep_for_gl_pixels_upload (gint pixels_rowstride,
gint bmp_width, gint pixels_src_x,
gint bmp_bpp, gint pixels_src_y,
gint src_x, gint pixels_bpp)
gint src_y,
gboolean pack)
{ {
const GLenum ALIGNMENT = pack ? GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
GL_PACK_ALIGNMENT : GL_UNPACK_ALIGNMENT;
const GLenum ROW_LENGTH = pack ? GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
GL_PACK_ROW_LENGTH : GL_UNPACK_ROW_LENGTH; GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
const GLenum SKIP_ROWS = pack ? if (!(pixels_rowstride & 0x7))
GL_PACK_SKIP_ROWS : GL_UNPACK_SKIP_ROWS; GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) );
else if (!(pixels_rowstride & 0x3))
const GLenum SKIP_PIXELS = pack ? GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 4) );
GL_PACK_SKIP_PIXELS : GL_UNPACK_SKIP_PIXELS; else if (!(pixels_rowstride & 0x1))
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 2) );
/* Encode the part of the rowstride that is a multiple of bmp_bpp in
ROW_LENGTH and the remainder in ALIGNMENT */
GE( glPixelStorei (ROW_LENGTH, bmp_rowstride / bmp_bpp) );
if (bmp_rowstride == bmp_width * bmp_bpp)
{
GE( glPixelStorei (ALIGNMENT, 1) );
}
else else
{ GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) );
if ((bmp_rowstride % 4) == 0) }
{
GE( glPixelStorei (ALIGNMENT, 4) );
}
else
{
if ((bmp_rowstride % 2) == 0)
GE( glPixelStorei (ALIGNMENT, 2) );
}
}
GE( glPixelStorei (SKIP_ROWS, src_y) ); static void
GE( glPixelStorei (SKIP_PIXELS, src_x) ); 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 * static guchar *
@ -270,17 +260,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
y * tex->slice_x_spans->len + x); y * tex->slice_x_spans->len + x);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
_cogl_subregion_gl_store_rules (tex->bitmap.rowstride, prep_for_gl_pixels_upload (tex->bitmap.rowstride,
tex->bitmap.width, x_span->start,
bpp, y_span->start,
x_span->start, bpp);
y_span->start,
FALSE);
/* Upload new image data */ /* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, GE( glTexSubImage2D (tex->gl_target, 0,
0,
0,
x_span->size - x_span->waste, x_span->size - x_span->waste,
y_span->size - y_span->waste, y_span->size - y_span->waste,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -305,13 +295,14 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
src += tex->bitmap.rowstride; src += tex->bitmap.rowstride;
} }
_cogl_subregion_gl_store_rules (x_span->waste * bpp, prep_for_gl_pixels_upload (x_span->waste * bpp,
x_span->waste, 0, /* src x */
bpp, 0, /* src y */
0, 0, FALSE); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, 0, x_span->size - x_span->waste,
0,
x_span->waste, x_span->waste,
y_span->size - y_span->waste, y_span->size - y_span->waste,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -339,13 +330,14 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
} }
} }
_cogl_subregion_gl_store_rules (x_span->size * bpp, prep_for_gl_pixels_upload (x_span->size * bpp,
x_span->size, 0, /* src x */
bpp, 0, /* src y */
0, 0, FALSE); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
0, y_span->size - y_span->waste, 0,
y_span->size - y_span->waste,
x_span->size, x_span->size,
y_span->waste, y_span->waste,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -401,17 +393,16 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
slice_bmp.height = y_span->size; slice_bmp.height = y_span->size;
slice_bmp.rowstride = bpp * slice_bmp.width; slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height); slice_bmp.height);
/* Setup gl alignment to 0,0 top-left corner */ /* Setup gl alignment to 0,0 top-left corner */
_cogl_subregion_gl_store_rules (slice_bmp.rowstride, prep_for_gl_pixels_download (slice_bmp.rowstride);
slice_bmp.width,
bpp, 0, 0, TRUE);
/* Download slice image data into temp bmp */ /* Download slice image data into temp bmp */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
GE (glGetTexImage (tex->gl_target, 0, GE (glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format, target_gl_format,
target_gl_type, target_gl_type,
slice_bmp.data) ); slice_bmp.data) );
@ -429,33 +420,20 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
} }
else else
{ {
/* Setup gl alignment to match rowstride and top-left corner */ GLvoid *dst = target_bmp->data
+ x_span->start * bpp
+ y_span->start * target_bmp->rowstride;
/* FIXME: for some strange reason any value other than 0 prep_for_gl_pixels_download (target_bmp->rowstride);
* for GL_PACK_SKIP_PIXELS or GL_PACK_SKIP_ROWS corrupts the
* memory. As a workaround we offset data pointer manually
_cogl_subregion_gl_store_rules (target_bmp->rowstride,
target_bmp->width,
bpp,
x_span->start,
y_span->start,
TRUE);*/
_cogl_subregion_gl_store_rules (target_bmp->rowstride,
target_bmp->width,
bpp,
0, 0,
TRUE);
/* Download slice image data */ /* Download slice image data */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glGetTexImage (tex->gl_target, 0, GE( glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format, target_gl_format,
target_gl_type, target_gl_type,
target_bmp->data + dst) );
x_span->start * bpp +
y_span->start * target_bmp->rowstride) );
} }
} }
} }
@ -550,13 +528,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
x_iter.index); x_iter.index);
/* Setup gl alignment to match rowstride and top-left corner */ /* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (source_bmp->rowstride,
_cogl_subregion_gl_store_rules (source_bmp->rowstride, source_x,
source_bmp->width, source_y,
bpp, bpp);
source_x,
source_y,
FALSE);
/* Upload new image data */ /* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
@ -599,13 +574,14 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
src += source_bmp->rowstride; src += source_bmp->rowstride;
} }
_cogl_subregion_gl_store_rules (x_span->waste * bpp, prep_for_gl_pixels_upload (x_span->waste * bpp,
x_span->waste, 0, /* src x */
bpp, 0, /* src y */
0, 0, FALSE); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, local_y, x_span->size - x_span->waste,
local_y,
x_span->waste, x_span->waste,
inter_h, inter_h,
source_gl_format, source_gl_format,
@ -650,13 +626,14 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
} }
} }
_cogl_subregion_gl_store_rules (copy_width * bpp, prep_for_gl_pixels_upload (copy_width * bpp,
copy_width, 0, /* src x */
bpp, 0, /* src y */
0, 0, FALSE); bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
local_x, y_span->size - y_span->waste, local_x,
y_span->size - y_span->waste,
copy_width, copy_width,
y_span->waste, y_span->waste,
source_gl_format, source_gl_format,
@ -764,7 +741,7 @@ _cogl_texture_size_supported (GLenum gl_target,
int width, int width,
int height) int height)
{ {
if (gl_target == GL_TEXTURE_2D) if (gl_target == GL_TEXTURE_2D)
{ {
/* Proxy texture allows for a quick check for supported size */ /* Proxy texture allows for a quick check for supported size */
@ -805,7 +782,7 @@ _cogl_texture_slices_create (CoglTexture *tex)
bpp = _cogl_get_format_bpp (tex->bitmap.format); bpp = _cogl_get_format_bpp (tex->bitmap.format);
/* Initialize size of largest slice according to supported features*/ /* Initialize size of largest slice according to supported features */
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)) if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
{ {
max_width = tex->bitmap.width; max_width = tex->bitmap.width;
@ -946,9 +923,12 @@ _cogl_texture_slices_create (CoglTexture *tex)
y_span->size - y_span->waste); y_span->size - y_span->waste);
#endif #endif
/* Setup texture parameters */ /* Setup texture parameters */
GE( glBindTexture (tex->gl_target, gl_handles[y * n_x_slices + x]) ); GE( glBindTexture (tex->gl_target,
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, tex->mag_filter) ); gl_handles[y * n_x_slices + x]) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, tex->min_filter) ); GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
tex->wrap_mode) ); tex->wrap_mode) );
@ -956,7 +936,8 @@ _cogl_texture_slices_create (CoglTexture *tex)
tex->wrap_mode) ); tex->wrap_mode) );
if (tex->auto_mipmap) if (tex->auto_mipmap)
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
GL_TRUE) );
/* Use a transparent border color so that we can leave the /* Use a transparent border color so that we can leave the
color buffer alone when using texture co-ordinates color buffer alone when using texture co-ordinates
@ -1414,10 +1395,10 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
CoglPixelFormat format) CoglPixelFormat format)
{ {
/* NOTE: width, height and internal format are not queriable /* NOTE: width, height and internal format are not queriable
in GLES, hence such a function prototype. However, here in GLES, hence such a function prototype. However, for
they are still queried from the texture for improved OpenGL they are still queried from the texture for improved
robustness and for completeness in case GLES 1.0 gets robustness and for completeness in case one day GLES gains
unsupported in favor of a new version and cleaner api support for them.
*/ */
GLenum gl_error = 0; GLenum gl_error = 0;
@ -1501,8 +1482,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
bpp = _cogl_get_format_bpp (format);
/* Create new texture */ /* Create new texture */
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
@ -1513,6 +1492,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
tex->is_foreign = TRUE; tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format; tex->bitmap.format = format;
tex->bitmap.width = gl_width - x_pot_waste; tex->bitmap.width = gl_width - x_pot_waste;
tex->bitmap.height = gl_height - y_pot_waste; tex->bitmap.height = gl_height - y_pot_waste;
@ -1737,9 +1717,11 @@ cogl_texture_set_filters (CoglHandle handle,
for (i=0; i<tex->slice_gl_handles->len; ++i) for (i=0; i<tex->slice_gl_handles->len; ++i)
{ {
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) ); 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_MAG_FILTER,
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, tex->min_filter) ); tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
} }
} }
@ -1935,7 +1917,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed tx2, CoglFixed tx2,
CoglFixed ty2) CoglFixed ty2)
{ {
CoglSpanIter iter_x , iter_y; CoglSpanIter iter_x , iter_y;
CoglFixed tw , th; CoglFixed tw , th;
CoglFixed tqx , tqy; CoglFixed tqx , tqy;
CoglFixed first_tx , first_ty; CoglFixed first_tx , first_ty;
@ -1944,8 +1926,12 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed slice_tx2 , slice_ty2; CoglFixed slice_tx2 , slice_ty2;
CoglFixed slice_qx1 , slice_qy1; CoglFixed slice_qx1 , slice_qy1;
CoglFixed slice_qx2 , slice_qy2; CoglFixed slice_qx2 , slice_qy2;
GLuint gl_handle; GLfloat tex_coords[8];
gulong enable_flags = 0; GLfloat quad_coords[8];
GLuint gl_handle;
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
| COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY);
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1953,9 +1939,8 @@ _cogl_texture_quad_sw (CoglTexture *tex,
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif #endif
/* Prepare GL state */
enable_flags |= COGL_ENABLE_TEXTURE_2D;
/* Prepare GL state */
if (ctx->color_alpha < 255 if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT) || tex->bitmap.format & COGL_A_BIT)
{ {
@ -1990,6 +1975,9 @@ _cogl_texture_quad_sw (CoglTexture *tex,
ty2 = temp; ty2 = temp;
} }
GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
/* Scale ratio from texture to quad widths */ /* Scale ratio from texture to quad widths */
tw = COGL_FIXED_FROM_INT (tex->bitmap.width); tw = COGL_FIXED_FROM_INT (tex->bitmap.width);
th = COGL_FIXED_FROM_INT (tex->bitmap.height); th = COGL_FIXED_FROM_INT (tex->bitmap.height);
@ -2087,21 +2075,17 @@ _cogl_texture_quad_sw (CoglTexture *tex,
#define CFX_F COGL_FIXED_TO_FLOAT #define CFX_F COGL_FIXED_TO_FLOAT
/* Draw textured quad */ /* Draw textured quad */
glBegin (GL_QUADS); tex_coords[0] = CFX_F(slice_tx1); tex_coords[1] = CFX_F(slice_ty2);
tex_coords[2] = CFX_F(slice_tx2); tex_coords[3] = CFX_F(slice_ty2);
tex_coords[4] = CFX_F(slice_tx1); tex_coords[5] = CFX_F(slice_ty1);
tex_coords[6] = CFX_F(slice_tx2); tex_coords[7] = CFX_F(slice_ty1);
glTexCoord2f (CFX_F(slice_tx1), CFX_F(slice_ty1)); quad_coords[0] = CFX_F(slice_qx1); quad_coords[1] = CFX_F(slice_qy2);
glVertex2f (CFX_F(slice_qx1), CFX_F(slice_qy1)); quad_coords[2] = CFX_F(slice_qx2); quad_coords[3] = CFX_F(slice_qy2);
quad_coords[4] = CFX_F(slice_qx1); quad_coords[5] = CFX_F(slice_qy1);
quad_coords[6] = CFX_F(slice_qx2); quad_coords[7] = CFX_F(slice_qy1);
glTexCoord2f (CFX_F(slice_tx1), CFX_F(slice_ty2)); GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
glVertex2f (CFX_F(slice_qx1), CFX_F(slice_qy2));
glTexCoord2f (CFX_F(slice_tx2), CFX_F(slice_ty2));
glVertex2f (CFX_F(slice_qx2), CFX_F(slice_qy2));
glTexCoord2f (CFX_F(slice_tx2), CFX_F(slice_ty1));
glVertex2f (CFX_F(slice_qx2), CFX_F(slice_qy1));
GE( glEnd () );
#undef CFX_F #undef CFX_F
} }
@ -2119,10 +2103,14 @@ _cogl_texture_quad_hw (CoglTexture *tex,
CoglFixed tx2, CoglFixed tx2,
CoglFixed ty2) CoglFixed ty2)
{ {
GLfloat tex_coords[8];
GLfloat quad_coords[8];
GLuint gl_handle;
CoglTexSliceSpan *x_span; CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span; CoglTexSliceSpan *y_span;
GLuint gl_handle; gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
gulong enable_flags = 0; | COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY);
#if COGL_DEBUG #if COGL_DEBUG
printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n"); printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n");
@ -2131,8 +2119,6 @@ _cogl_texture_quad_hw (CoglTexture *tex,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Prepare GL state */ /* Prepare GL state */
enable_flags |= COGL_ENABLE_TEXTURE_2D;
if (ctx->color_alpha < 255 if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT) || tex->bitmap.format & COGL_A_BIT)
{ {
@ -2144,10 +2130,14 @@ _cogl_texture_quad_hw (CoglTexture *tex,
cogl_enable (enable_flags); cogl_enable (enable_flags);
GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
/* Pick and bind opengl texture object */ /* Pick and bind opengl texture object */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
/* Don't include the waste in the texture coordinates */
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
@ -2160,21 +2150,17 @@ _cogl_texture_quad_hw (CoglTexture *tex,
#define CFX_F(x) COGL_FIXED_TO_FLOAT(x) #define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
/* Draw textured quad */ /* Draw textured quad */
glBegin (GL_QUADS); tex_coords[0] = CFX_F(tx1); tex_coords[1] = CFX_F(ty2);
tex_coords[2] = CFX_F(tx2); tex_coords[3] = CFX_F(ty2);
tex_coords[4] = CFX_F(tx1); tex_coords[5] = CFX_F(ty1);
tex_coords[6] = CFX_F(tx2); tex_coords[7] = CFX_F(ty1);
glTexCoord2f (CFX_F(tx1), CFX_F(ty1)); quad_coords[0] = CFX_F(x1); quad_coords[1] = CFX_F(y2);
glVertex2f (CFX_F(x1), CFX_F(y1)); quad_coords[2] = CFX_F(x2); quad_coords[3] = CFX_F(y2);
quad_coords[4] = CFX_F(x1); quad_coords[5] = CFX_F(y1);
quad_coords[6] = CFX_F(x2); quad_coords[7] = CFX_F(y1);
glTexCoord2f (CFX_F(tx1), CFX_F(ty2)); GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
glVertex2f (CFX_F(x1), CFX_F(y2));
glTexCoord2f (CFX_F(tx2), CFX_F(ty2));
glVertex2f (CFX_F(x2), CFX_F(y2));
glTexCoord2f (CFX_F(tx2), CFX_F(ty1));
glVertex2f (CFX_F(x2), CFX_F(y1));
GE( glEnd () );
#undef CFX_F #undef CFX_F
} }
@ -2216,11 +2202,11 @@ cogl_texture_rectangle (CoglHandle handle,
} }
else else
{ {
if (tex->slice_gl_handles->len == 1 && if (tex->slice_gl_handles->len == 1
tx1 >= -COGL_FIXED_1 && && tx1 >= -COGL_FIXED_1
tx2 <= COGL_FIXED_1 && && tx2 <= COGL_FIXED_1
ty1 >= -COGL_FIXED_1 && && ty1 >= -COGL_FIXED_1
ty2 <= COGL_FIXED_1) && ty2 <= COGL_FIXED_1)
{ {
_cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2); _cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
} }
@ -2238,10 +2224,11 @@ cogl_texture_polygon (CoglHandle handle,
gboolean use_color) gboolean use_color)
{ {
CoglTexture *tex; CoglTexture *tex;
int i, x, y, vnum; int i, x, y;
GLuint gl_handle; GLuint gl_handle;
CoglTexSliceSpan *y_span, *x_span; CoglTexSliceSpan *y_span, *x_span;
gulong enable_flags; gulong enable_flags;
CoglTextureGLVertex *p;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -2271,14 +2258,48 @@ cogl_texture_polygon (CoglHandle handle,
return; return;
} }
tex = _cogl_texture_pointer_from_handle (handle); /* Make sure there is enough space in the global texture vertex
array. This is used so we can render the polygon with a single
call to OpenGL but still support any number of vertices */
if (ctx->texture_vertices_size < n_vertices)
{
guint nsize = ctx->texture_vertices_size;
if (nsize == 0)
nsize = 1;
do
nsize *= 2;
while (nsize < n_vertices);
ctx->texture_vertices_size = nsize;
ctx->texture_vertices = g_realloc (ctx->texture_vertices,
nsize
* sizeof (CoglTextureGLVertex));
}
/* Prepare GL state */ /* Prepare GL state */
enable_flags = COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_BLEND; enable_flags = (COGL_ENABLE_TEXTURE_2D
| COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY
| COGL_ENABLE_BLEND);
if (ctx->enable_backface_culling) if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING; enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
if (use_color)
{
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
GE( glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].c) );
}
GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].v) );
GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].t) );
cogl_enable (enable_flags); cogl_enable (enable_flags);
/* Temporarily change the wrapping mode on all of the slices to use /* Temporarily change the wrapping mode on all of the slices to use
@ -2308,34 +2329,30 @@ cogl_texture_polygon (CoglHandle handle,
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i++); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i++);
GE( glBindTexture (tex->gl_target, gl_handle) ); /* Convert the vertices into an array of GLfloats ready to pass to
OpenGL */
glBegin (GL_TRIANGLE_FAN); for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++)
for (vnum = 0; vnum < n_vertices; vnum++)
{ {
GLfloat tx, ty; #define CFX_F COGL_FIXED_TO_FLOAT
if (use_color) p->v[0] = CFX_F(vertices[i].x);
cogl_set_source_color (&vertices[vnum].color); p->v[1] = CFX_F(vertices[i].y);
p->v[2] = CFX_F(vertices[i].z);
p->t[0] = CFX_F(vertices[i].tx
* (x_span->size - x_span->waste) / x_span->size);
p->t[1] = CFX_F(vertices[i].ty
* (y_span->size - y_span->waste) / y_span->size);
p->c[0] = cogl_color_get_red_byte(&vertices[i].color);
p->c[1] = cogl_color_get_green_byte(&vertices[i].color);
p->c[2] = cogl_color_get_blue_byte(&vertices[i].color);
p->c[3] = cogl_color_get_alpha_byte(&vertices[i].color);
/* Transform the texture co-ordinates so they are #undef CFX_F
relative to the slice */
tx = (COGL_FIXED_TO_FLOAT (vertices[vnum].tx)
- x_span->start / (GLfloat) tex->bitmap.width)
* tex->bitmap.width / x_span->size;
ty = (COGL_FIXED_TO_FLOAT (vertices[vnum].ty)
- y_span->start / (GLfloat) tex->bitmap.height)
* tex->bitmap.height / y_span->size;
glTexCoord2f (tx, ty);
glVertex3f (COGL_FIXED_TO_FLOAT (vertices[vnum].x),
COGL_FIXED_TO_FLOAT (vertices[vnum].y),
COGL_FIXED_TO_FLOAT (vertices[vnum].z));
} }
GE( glEnd () ); GE( glBindTexture (tex->gl_target, gl_handle) );
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
} }
} }

View File

@ -327,6 +327,9 @@ cogl_enable (gulong flags)
COGL_ENABLE_TEXCOORD_ARRAY, COGL_ENABLE_TEXCOORD_ARRAY,
GL_TEXTURE_COORD_ARRAY); GL_TEXTURE_COORD_ARRAY);
cogl_toggle_client_flag (ctx, flags,
COGL_ENABLE_COLOR_ARRAY,
GL_COLOR_ARRAY);
} }
gulong gulong

View File

@ -32,9 +32,9 @@
typedef struct typedef struct
{ {
GLfixed v[3]; GLfloat v[3];
GLfixed t[2]; GLfloat t[2];
GLfixed c[4]; GLubyte c[4];
} CoglTextureGLVertex; } CoglTextureGLVertex;
typedef struct typedef struct

View File

@ -55,6 +55,7 @@ struct _CoglTexture
COGLenum min_filter; COGLenum min_filter;
COGLenum mag_filter; COGLenum mag_filter;
gboolean is_foreign; gboolean is_foreign;
GLint wrap_mode;
gboolean auto_mipmap; gboolean auto_mipmap;
}; };

View File

@ -39,6 +39,13 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#define glVertexPointer cogl_wrap_glVertexPointer
#define glTexCoordPointer cogl_wrap_glTexCoordPointer
#define glColorPointer cogl_wrap_glColorPointer
#define glDrawArrays cogl_wrap_glDrawArrays
#define glTexParameteri cogl_wrap_glTexParameteri
/* /*
#define COGL_DEBUG 1 #define COGL_DEBUG 1
@ -174,6 +181,36 @@ _cogl_span_iter_end (CoglSpanIter *iter)
return iter->pos >= iter->cover_end; 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 * static guchar *
_cogl_texture_allocate_waste_buffer (CoglTexture *tex) _cogl_texture_allocate_waste_buffer (CoglTexture *tex)
{ {
@ -214,10 +251,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
guchar *waste_buf; guchar *waste_buf;
CoglBitmap slice_bmp; CoglBitmap slice_bmp;
/* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture
image is not sliced */
bpp = _cogl_get_format_bpp (tex->bitmap.format); bpp = _cogl_get_format_bpp (tex->bitmap.format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex); waste_buf = _cogl_texture_allocate_waste_buffer (tex);
@ -236,13 +269,23 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x); y * tex->slice_x_spans->len + x);
/* 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 */ /* Setup temp bitmap for slice subregion */
slice_bmp.format = tex->bitmap.format; slice_bmp.format = tex->bitmap.format;
slice_bmp.width = x_span->size - x_span->waste; slice_bmp.width = x_span->size - x_span->waste;
slice_bmp.height = y_span->size - y_span->waste; slice_bmp.height = y_span->size - y_span->waste;
slice_bmp.rowstride = bpp * slice_bmp.width; slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height); 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 */ /* Copy subregion data */
_cogl_bitmap_copy_subregion (&tex->bitmap, _cogl_bitmap_copy_subregion (&tex->bitmap,
@ -257,9 +300,9 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) ); GE( glTexSubImage2D (tex->gl_target, 0,
0,
GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 0,
slice_bmp.width, slice_bmp.width,
slice_bmp.height, slice_bmp.height,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -284,8 +327,14 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
src += tex->bitmap.rowstride; 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, GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, 0, x_span->size - x_span->waste,
0,
x_span->waste, x_span->waste,
y_span->size - y_span->waste, y_span->size - y_span->waste,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -313,8 +362,14 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
} }
} }
prep_for_gl_pixels_upload (x_span->size * bpp,
0, /* src x */
0, /* src y */
bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
0, y_span->size - y_span->waste, 0,
y_span->size - y_span->waste,
x_span->size, x_span->size,
y_span->waste, y_span->waste,
tex->gl_format, tex->gl_type, tex->gl_format, tex->gl_type,
@ -371,7 +426,7 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
0, 0, COGL_FIXED_1, COGL_FIXED_1); 0, 0, COGL_FIXED_1, COGL_FIXED_1);
/* Read into target bitmap */ /* Read into target bitmap */
GE( glPixelStorei (GL_PACK_ALIGNMENT, 1) ); prep_for_gl_pixels_download (tex->bitmap.rowstride);
GE( glReadPixels (viewport[0], viewport[1], GE( glReadPixels (viewport[0], viewport[1],
tex->bitmap.width, tex->bitmap.width,
tex->bitmap.height, tex->bitmap.height,
@ -430,7 +485,7 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride *
rect_bmp.height); rect_bmp.height);
GE( glPixelStorei (GL_PACK_ALIGNMENT, 1) ); prep_for_gl_pixels_download (rect_bmp.rowstride);
GE( glReadPixels (viewport[0], viewport[1], GE( glReadPixels (viewport[0], viewport[1],
rect_bmp.width, rect_bmp.width,
rect_bmp.height, rect_bmp.height,
@ -603,10 +658,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
waste_buf = _cogl_texture_allocate_waste_buffer (tex); waste_buf = _cogl_texture_allocate_waste_buffer (tex);
/* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture
image is not sliced */
/* Iterate vertical spans */ /* Iterate vertical spans */
for (source_y = src_y, for (source_y = src_y,
_cogl_span_iter_begin (&y_iter, tex->slice_y_spans, _cogl_span_iter_begin (&y_iter, tex->slice_y_spans,
@ -618,12 +669,12 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&y_iter), _cogl_span_iter_next (&y_iter),
source_y += inter_h ) source_y += inter_h )
{ {
/* Skip non-intersecting ones */ /* Discard slices out of the subregion early */
if (!y_iter.intersects) if (!y_iter.intersects)
{ {
inter_h = 0; inter_h = 0;
continue; continue;
} }
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan,
y_iter.index); y_iter.index);
@ -639,33 +690,37 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&x_iter), _cogl_span_iter_next (&x_iter),
source_x += inter_w ) source_x += inter_w )
{ {
/* Skip non-intersecting ones */ /* Discard slices out of the subregion early */
if (!x_iter.intersects) if (!x_iter.intersects)
{ {
inter_w = 0; inter_w = 0;
continue; continue;
} }
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan,
x_iter.index); x_iter.index);
/* Pick intersection width and height */ /* Pick intersection width and height */
inter_w = COGL_FIXED_TO_INT (x_iter.intersect_end - inter_w = COGL_FIXED_TO_INT (x_iter.intersect_end -
x_iter.intersect_start); x_iter.intersect_start);
inter_h = COGL_FIXED_TO_INT (y_iter.intersect_end - inter_h = COGL_FIXED_TO_INT (y_iter.intersect_end -
y_iter.intersect_start); y_iter.intersect_start);
/* Localize intersection top-left corner to slice*/ /* Localize intersection top-left corner to slice*/
local_x = COGL_FIXED_TO_INT (x_iter.intersect_start - local_x = COGL_FIXED_TO_INT (x_iter.intersect_start -
x_iter.pos); x_iter.pos);
local_y = COGL_FIXED_TO_INT (y_iter.intersect_start - local_y = COGL_FIXED_TO_INT (y_iter.intersect_start -
y_iter.pos); y_iter.pos);
/* Pick slice GL handle */ /* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y_iter.index * tex->slice_x_spans->len + y_iter.index * tex->slice_x_spans->len +
x_iter.index); x_iter.index);
/* 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 */ /* Setup temp bitmap for slice subregion */
slice_bmp.format = tex->bitmap.format; slice_bmp.format = tex->bitmap.format;
slice_bmp.width = inter_w; slice_bmp.width = inter_w;
@ -674,6 +729,12 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height); 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 */ /* Copy subregion data */
_cogl_bitmap_copy_subregion (source_bmp, _cogl_bitmap_copy_subregion (source_bmp,
&slice_bmp, &slice_bmp,
@ -684,8 +745,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
slice_bmp.height); slice_bmp.height);
/* Upload new image data */ /* Upload new image data */
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) );
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
@ -703,14 +762,20 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
&& local_x < x_span->size - x_span->waste && local_x < x_span->size - x_span->waste
&& local_x + inter_w >= x_span->size - x_span->waste) && local_x + inter_w >= x_span->size - x_span->waste)
{ {
const guchar *src = source_bmp->data const guchar *src;
+ (src_y + COGL_FIXED_TO_INT (y_iter.intersect_start) guchar *dst;
- dst_y) * source_bmp->rowstride
+ (src_x + x_span->start + x_span->size - x_span->waste
- dst_x - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy; guint wx, wy;
src = source_bmp->data
+ (src_y + COGL_FIXED_TO_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 (wy = 0; wy < inter_h; wy++)
{ {
for (wx = 0; wx < x_span->waste; wx++) for (wx = 0; wx < x_span->waste; wx++)
@ -721,8 +786,14 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
src += source_bmp->rowstride; 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, GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, local_y, x_span->size - x_span->waste,
local_y,
x_span->waste, x_span->waste,
inter_h, inter_h,
source_gl_format, source_gl_format,
@ -735,15 +806,21 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
&& local_y < y_span->size - y_span->waste && local_y < y_span->size - y_span->waste
&& local_y + inter_h >= y_span->size - y_span->waste) && local_y + inter_h >= y_span->size - y_span->waste)
{ {
const guchar *src = source_bmp->data const guchar *src;
+ (src_x + COGL_FIXED_TO_INT (x_iter.intersect_start) guchar *dst;
- dst_x) * bpp
+ (src_y + y_span->start + y_span->size - y_span->waste
- dst_y - 1) * source_bmp->rowstride;
guchar *dst = waste_buf;
guint wy, wx; guint wy, wx;
guint copy_width; guint copy_width;
src = source_bmp->data
+ (src_x + COGL_FIXED_TO_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) if (local_x + inter_w >= x_span->size - x_span->waste)
copy_width = x_span->size - local_x; copy_width = x_span->size - local_x;
else else
@ -761,8 +838,14 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
} }
} }
prep_for_gl_pixels_upload (copy_width * bpp,
0, /* src x */
0, /* src y */
bpp);
GE( glTexSubImage2D (tex->gl_target, 0, GE( glTexSubImage2D (tex->gl_target, 0,
local_x, y_span->size - y_span->waste, local_x,
y_span->size - y_span->waste,
copy_width, copy_width,
y_span->waste, y_span->waste,
source_gl_format, source_gl_format,
@ -784,6 +867,41 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
return 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 static gint
_cogl_pot_slices_for_size (gint size_to_fill, _cogl_pot_slices_for_size (gint size_to_fill,
gint max_span_size, gint max_span_size,
@ -863,10 +981,20 @@ _cogl_texture_slices_create (CoglTexture *tex)
bpp = _cogl_get_format_bpp (tex->bitmap.format); bpp = _cogl_get_format_bpp (tex->bitmap.format);
/* Initialize size of largest slice according to supported features */ /* Initialize size of largest slice according to supported features */
max_width = cogl_util_next_p2 (tex->bitmap.width); if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
max_height = cogl_util_next_p2 (tex->bitmap.height); {
tex->gl_target = GL_TEXTURE_2D; max_width = tex->bitmap.width;
slices_for_size = _cogl_pot_slices_for_size; 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 */ /* Negative number means no slicing forced by the user */
if (tex->max_waste <= -1) if (tex->max_waste <= -1)
@ -961,6 +1089,14 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices); g_array_set_size (tex->slice_gl_handles, n_slices);
/* Hardware repeated tiling if supported, else tile in software*/
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
&& n_slices == 1)
tex->wrap_mode = GL_REPEAT;
else
tex->wrap_mode = GL_CLAMP_TO_EDGE;
/* Generate a "working set" of GL texture objects /* Generate a "working set" of GL texture objects
* (some implementations might supported faster * (some implementations might supported faster
* re-binding between textures inside a set) */ * re-binding between textures inside a set) */
@ -988,19 +1124,19 @@ _cogl_texture_slices_create (CoglTexture *tex)
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target,
gl_handles[y * n_x_slices + x], gl_handles[y * n_x_slices + x],
tex->gl_intformat) ); tex->gl_intformat) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
tex->mag_filter) ); tex->wrap_mode) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
tex->min_filter) ); tex->wrap_mode) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE) );
if (tex->auto_mipmap) if (tex->auto_mipmap)
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
GL_TRUE) ); GL_TRUE) );
/* Pass NULL data to init size and internal format */ /* Pass NULL data to init size and internal format */
GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
@ -1033,13 +1169,20 @@ _cogl_texture_slices_free (CoglTexture *tex)
} }
} }
static gboolean
_cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
CoglPixelFormat *out_format)
{
return TRUE;
}
static CoglPixelFormat static CoglPixelFormat
_cogl_pixel_format_to_gl (CoglPixelFormat format, _cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum *out_glintformat, GLenum *out_glintformat,
GLenum *out_glformat, GLenum *out_glformat,
GLenum *out_gltype) GLenum *out_gltype)
{ {
CoglPixelFormat required_format = format; CoglPixelFormat required_format;
GLenum glintformat = 0; GLenum glintformat = 0;
GLenum glformat = 0; GLenum glformat = 0;
GLenum gltype = 0; GLenum gltype = 0;
@ -1050,6 +1193,10 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
if (format & COGL_PREMULT_BIT) if (format & COGL_PREMULT_BIT)
format = (format & COGL_UNPREMULT_MASK); format = (format & COGL_UNPREMULT_MASK);
/* Everything else accepted
* (FIXME: check YUV support) */
required_format = format;
/* Find GL equivalents */ /* Find GL equivalents */
switch (format) switch (format)
{ {
@ -1213,6 +1360,7 @@ cogl_texture_new_with_size (guint width,
&tex->gl_format, &tex->gl_format,
&tex->gl_type); &tex->gl_type);
/* Create slices for the given format and size */
if (!_cogl_texture_slices_create (tex)) if (!_cogl_texture_slices_create (tex))
{ {
_cogl_texture_free (tex); _cogl_texture_free (tex);
@ -1294,7 +1442,7 @@ cogl_texture_new_from_data (guint width,
_cogl_texture_bitmap_free (tex); _cogl_texture_bitmap_free (tex);
return _cogl_texture_handle_new (tex);; return _cogl_texture_handle_new (tex);
} }
CoglHandle CoglHandle
@ -1382,8 +1530,19 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GLuint y_pot_waste, GLuint y_pot_waste,
CoglPixelFormat format) 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; GLenum gl_error = 0;
GLboolean gl_istexture; GLboolean gl_istexture;
GLint gl_compressed = GL_FALSE;
GLint gl_int_format = 0;
GLint gl_width = 0;
GLint gl_height = 0;
GLint gl_min_filter; GLint gl_min_filter;
GLint gl_mag_filter; GLint gl_mag_filter;
GLint gl_gen_mipmap; GLint gl_gen_mipmap;
@ -1410,7 +1569,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Obtain texture parameters /* Obtain texture parameters
(only level 0 we are interested in) */ (only level 0 we are interested in) */
/* These are not queriable in GLES :( #if HAVE_COGL_GL
GE( glGetTexLevelParameteriv (gl_target, 0, GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_COMPRESSED, GL_TEXTURE_COMPRESSED,
&gl_compressed) ); &gl_compressed) );
@ -1418,28 +1577,52 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GE( glGetTexLevelParameteriv (gl_target, 0, GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_INTERNAL_FORMAT, GL_TEXTURE_INTERNAL_FORMAT,
&gl_int_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, GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MIN_FILTER,
&gl_min_filter)); &gl_min_filter) );
GE( glGetTexParameteriv (gl_target, GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MAG_FILTER,
&gl_mag_filter)); &gl_mag_filter) );
GE( glGetTexParameteriv (gl_target, GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP, GL_GENERATE_MIPMAP,
&gl_gen_mipmap) ); &gl_gen_mipmap) );
/* Validate width and height */ /* Validate width and height */
if (width <= 0 || height <= 0) if (gl_width <= 0 || gl_height <= 0)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
/* Validate pot waste */ /* Validate pot waste */
if (x_pot_waste < 0 || x_pot_waste >= width || if (x_pot_waste < 0 || x_pot_waste >= gl_width ||
y_pot_waste < 0 || y_pot_waste >= height) y_pot_waste < 0 || y_pot_waste >= gl_height)
return COGL_INVALID_HANDLE; 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 */ /* Create new texture */
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
@ -1452,15 +1635,15 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format; tex->bitmap.format = format;
tex->bitmap.width = width; tex->bitmap.width = gl_width - x_pot_waste;
tex->bitmap.height = height; tex->bitmap.height = gl_height - y_pot_waste;
tex->bitmap.rowstride = tex->bitmap.width * bpp; tex->bitmap.rowstride = tex->bitmap.width * bpp;
tex->bitmap_owner = FALSE; tex->bitmap_owner = FALSE;
tex->gl_target = gl_target; tex->gl_target = gl_target;
tex->gl_intformat = 0; tex->gl_intformat = gl_int_format;
tex->gl_format = 0; tex->gl_format = gl_int_format;
tex->gl_type = 0; tex->gl_type = GL_UNSIGNED_BYTE;
tex->min_filter = gl_min_filter; tex->min_filter = gl_min_filter;
tex->mag_filter = gl_mag_filter; tex->mag_filter = gl_mag_filter;
@ -1481,59 +1664,37 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Store info for a single slice */ /* Store info for a single slice */
x_span.start = 0; x_span.start = 0;
x_span.size = width + x_pot_waste; x_span.size = gl_width;
x_span.waste = x_pot_waste; x_span.waste = x_pot_waste;
g_array_append_val (tex->slice_x_spans, x_span); g_array_append_val (tex->slice_x_spans, x_span);
y_span.start = 0; y_span.start = 0;
y_span.size = height + x_pot_waste; y_span.size = gl_height;
y_span.waste = y_pot_waste; y_span.waste = y_pot_waste;
g_array_append_val (tex->slice_y_spans, y_span); g_array_append_val (tex->slice_y_spans, y_span);
g_array_append_val (tex->slice_gl_handles, gl_handle); g_array_append_val (tex->slice_gl_handles, gl_handle);
/* Force appropriate wrap parameter */ /* Force appropriate wrap parameter */
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) &&
GL_CLAMP_TO_EDGE) ); gl_target == GL_TEXTURE_2D)
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, {
GL_CLAMP_TO_EDGE) ); /* Hardware repeated tiling */
tex->wrap_mode = GL_REPEAT;
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_REPEAT) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_REPEAT) );
}
else
{
/* Any tiling will be done in software */
tex->wrap_mode = GL_CLAMP_TO_EDGE;
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) );
}
return _cogl_texture_handle_new (tex); return _cogl_texture_handle_new (tex);
} }
void
cogl_texture_get_properties (CoglHandle handle,
guint *out_width,
guint *out_height,
CoglPixelFormat *out_format,
guint *out_rowstride,
guint *out_max_waste)
{
CoglTexture *tex;
/* Check if valid texture handle */
if (!cogl_is_texture (handle))
return;
tex = _cogl_texture_pointer_from_handle (handle);
/* Output requested properties */
if (out_width != NULL)
*out_width = tex->bitmap.width;
if (out_height != NULL)
*out_height = tex->bitmap.height;
if (out_format != NULL)
*out_format = tex->bitmap.format;
if (out_rowstride != NULL)
*out_rowstride = tex->bitmap.rowstride;
if (out_max_waste != NULL)
*out_max_waste = tex->max_waste;
}
guint guint
cogl_texture_get_width (CoglHandle handle) cogl_texture_get_width (CoglHandle handle)
{ {
@ -1698,10 +1859,10 @@ cogl_texture_set_filters (CoglHandle handle,
{ {
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) ); GE( glBindTexture (tex->gl_target, gl_handle) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) ); tex->mag_filter) );
GE( cogl_wrap_glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) ); tex->min_filter) );
} }
} }
@ -1897,7 +2058,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed tx2, CoglFixed tx2,
CoglFixed ty2) CoglFixed ty2)
{ {
CoglSpanIter iter_x , iter_y; CoglSpanIter iter_x , iter_y;
CoglFixed tw , th; CoglFixed tw , th;
CoglFixed tqx , tqy; CoglFixed tqx , tqy;
CoglFixed first_tx , first_ty; CoglFixed first_tx , first_ty;
@ -1906,18 +2067,19 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed slice_tx2 , slice_ty2; CoglFixed slice_tx2 , slice_ty2;
CoglFixed slice_qx1 , slice_qy1; CoglFixed slice_qx1 , slice_qy1;
CoglFixed slice_qx2 , slice_qy2; CoglFixed slice_qx2 , slice_qy2;
GLfixed tex_coords[8]; GLfloat tex_coords[8];
GLfixed quad_coords[8]; GLfloat quad_coords[8];
GLuint gl_handle; GLuint gl_handle;
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
| COGL_ENABLE_VERTEX_ARRAY | COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY); | COGL_ENABLE_TEXCOORD_ARRAY);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
#if COGL_DEBUG #if COGL_DEBUG
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif #endif
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Prepare GL state */ /* Prepare GL state */
if (ctx->color_alpha < 255 if (ctx->color_alpha < 255
@ -1954,15 +2116,15 @@ _cogl_texture_quad_sw (CoglTexture *tex,
ty2 = temp; ty2 = temp;
} }
GE( cogl_wrap_glTexCoordPointer (2, GL_FIXED, 0, tex_coords) ); GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, quad_coords) ); GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
/* Scale ratio from texture to quad widths */ /* Scale ratio from texture to quad widths */
tw = COGL_FIXED_FROM_INT (tex->bitmap.width); tw = COGL_FIXED_FROM_INT (tex->bitmap.width);
th = COGL_FIXED_FROM_INT (tex->bitmap.height); th = COGL_FIXED_FROM_INT (tex->bitmap.height);
tqx = COGL_FIXED_DIV (x2-x1, COGL_FIXED_MUL (tw, (tx2 - tx1))); tqx = COGL_FIXED_DIV (x2 - x1, COGL_FIXED_MUL (tw, (tx2 - tx1)));
tqy = COGL_FIXED_DIV (y2-y1, COGL_FIXED_MUL (th, (ty2 - ty1))); tqy = COGL_FIXED_DIV (y2 - y1, COGL_FIXED_MUL (th, (ty2 - ty1)));
/* Integral texture coordinate for first tile */ /* Integral texture coordinate for first tile */
first_tx = COGL_FIXED_FROM_INT (COGL_FIXED_FLOOR (tx1)); first_tx = COGL_FIXED_FROM_INT (COGL_FIXED_FLOOR (tx1));
@ -2001,7 +2163,8 @@ _cogl_texture_quad_sw (CoglTexture *tex,
slice_ty1 = iter_y.intersect_start - iter_y.pos; slice_ty1 = iter_y.intersect_start - iter_y.pos;
slice_ty2 = iter_y.intersect_end - iter_y.pos; slice_ty2 = iter_y.intersect_end - iter_y.pos;
/* Normalize texture coordinates to current slice */ /* Normalize texture coordinates to current slice
(rectangle texture targets take denormalized) */
slice_ty1 /= iter_y.span->size; slice_ty1 /= iter_y.span->size;
slice_ty2 /= iter_y.span->size; slice_ty2 /= iter_y.span->size;
@ -2026,9 +2189,10 @@ _cogl_texture_quad_sw (CoglTexture *tex,
slice_tx1 = iter_x.intersect_start - iter_x.pos; slice_tx1 = iter_x.intersect_start - iter_x.pos;
slice_tx2 = iter_x.intersect_end - iter_x.pos; slice_tx2 = iter_x.intersect_end - iter_x.pos;
/* Normalize texture coordinates to current slice */ /* Normalize texture coordinates to current slice
slice_tx1 /= iter_x.span->size; (rectangle texture targets take denormalized) */
slice_tx2 /= iter_x.span->size; slice_tx1 /= iter_x.span->size;
slice_tx2 /= iter_x.span->size;
#if COGL_DEBUG #if COGL_DEBUG
printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index); printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index);
@ -2050,18 +2214,22 @@ _cogl_texture_quad_sw (CoglTexture *tex,
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
#define CFX_F COGL_FIXED_TO_FLOAT
/* Draw textured quad */ /* Draw textured quad */
tex_coords[0] = slice_tx1; tex_coords[1] = slice_ty2; tex_coords[0] = CFX_F(slice_tx1); tex_coords[1] = CFX_F(slice_ty2);
tex_coords[2] = slice_tx2; tex_coords[3] = slice_ty2; tex_coords[2] = CFX_F(slice_tx2); tex_coords[3] = CFX_F(slice_ty2);
tex_coords[4] = slice_tx1; tex_coords[5] = slice_ty1; tex_coords[4] = CFX_F(slice_tx1); tex_coords[5] = CFX_F(slice_ty1);
tex_coords[6] = slice_tx2; tex_coords[7] = slice_ty1; tex_coords[6] = CFX_F(slice_tx2); tex_coords[7] = CFX_F(slice_ty1);
quad_coords[0] = slice_qx1; quad_coords[1] = slice_qy2; quad_coords[0] = CFX_F(slice_qx1); quad_coords[1] = CFX_F(slice_qy2);
quad_coords[2] = slice_qx2; quad_coords[3] = slice_qy2; quad_coords[2] = CFX_F(slice_qx2); quad_coords[3] = CFX_F(slice_qy2);
quad_coords[4] = slice_qx1; quad_coords[5] = slice_qy1; quad_coords[4] = CFX_F(slice_qx1); quad_coords[5] = CFX_F(slice_qy1);
quad_coords[6] = slice_qx2; quad_coords[7] = slice_qy1; quad_coords[6] = CFX_F(slice_qx2); quad_coords[7] = CFX_F(slice_qy1);
GE (cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
#undef CFX_F
} }
} }
} }
@ -2077,8 +2245,8 @@ _cogl_texture_quad_hw (CoglTexture *tex,
CoglFixed tx2, CoglFixed tx2,
CoglFixed ty2) CoglFixed ty2)
{ {
GLfixed tex_coords[8]; GLfloat tex_coords[8];
GLfixed quad_coords[8]; GLfloat quad_coords[8];
GLuint gl_handle; GLuint gl_handle;
CoglTexSliceSpan *x_span; CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span; CoglTexSliceSpan *y_span;
@ -2104,8 +2272,8 @@ _cogl_texture_quad_hw (CoglTexture *tex,
cogl_enable (enable_flags); cogl_enable (enable_flags);
GE( cogl_wrap_glTexCoordPointer (2, GL_FIXED, 0, tex_coords) ); GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, quad_coords) ); GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
/* Pick and bind opengl texture object */ /* Pick and bind opengl texture object */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
@ -2115,23 +2283,29 @@ _cogl_texture_quad_hw (CoglTexture *tex,
/* Don't include the waste in the texture coordinates */ /* Don't include the waste in the texture coordinates */
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
/* Don't include the waste in the texture coordinates */
tx1 = tx1 * (x_span->size - x_span->waste) / x_span->size; tx1 = tx1 * (x_span->size - x_span->waste) / x_span->size;
tx2 = tx2 * (x_span->size - x_span->waste) / x_span->size; tx2 = tx2 * (x_span->size - x_span->waste) / x_span->size;
ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size; ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size;
ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size; ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size;
#define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
/* Draw textured quad */ /* Draw textured quad */
tex_coords[0] = tx1; tex_coords[1] = ty2; tex_coords[0] = CFX_F(tx1); tex_coords[1] = CFX_F(ty2);
tex_coords[2] = tx2; tex_coords[3] = ty2; tex_coords[2] = CFX_F(tx2); tex_coords[3] = CFX_F(ty2);
tex_coords[4] = tx1; tex_coords[5] = ty1; tex_coords[4] = CFX_F(tx1); tex_coords[5] = CFX_F(ty1);
tex_coords[6] = tx2; tex_coords[7] = ty1; tex_coords[6] = CFX_F(tx2); tex_coords[7] = CFX_F(ty1);
quad_coords[0] = x1; quad_coords[1] = y2; quad_coords[0] = CFX_F(x1); quad_coords[1] = CFX_F(y2);
quad_coords[2] = x2; quad_coords[3] = y2; quad_coords[2] = CFX_F(x2); quad_coords[3] = CFX_F(y2);
quad_coords[4] = x1; quad_coords[5] = y1; quad_coords[4] = CFX_F(x1); quad_coords[5] = CFX_F(y1);
quad_coords[6] = x2; quad_coords[7] = y1; quad_coords[6] = CFX_F(x2); quad_coords[7] = CFX_F(y1);
GE (cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
#undef CFX_F
} }
void void
@ -2163,16 +2337,26 @@ cogl_texture_rectangle (CoglHandle handle,
if (tx1 == tx2 || ty1 == ty2) if (tx1 == tx2 || ty1 == ty2)
return; return;
/* Tile textured quads */ /* Pick tiling mode according to hw support */
if (tex->slice_gl_handles->len == 1 && if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
tx1 >= -COGL_FIXED_1 && tx2 <= COGL_FIXED_1 && && tex->slice_gl_handles->len == 1)
ty1 >= -COGL_FIXED_1 && ty2 <= COGL_FIXED_1)
{ {
_cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2); _cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
} }
else else
{ {
_cogl_texture_quad_sw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2); if (tex->slice_gl_handles->len == 1
&& tx1 >= -COGL_FIXED_1
&& tx2 <= COGL_FIXED_1
&& ty1 >= -COGL_FIXED_1
&& ty2 <= COGL_FIXED_1)
{
_cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
}
else
{
_cogl_texture_quad_sw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
}
} }
} }
@ -2182,13 +2366,12 @@ cogl_texture_polygon (CoglHandle handle,
CoglTextureVertex *vertices, CoglTextureVertex *vertices,
gboolean use_color) gboolean use_color)
{ {
CoglTexture *tex; CoglTexture *tex;
GLuint gl_handle; int i;
gulong enable_flags; GLuint gl_handle;
int i; CoglTexSliceSpan *y_span, *x_span;
gulong enable_flags;
CoglTextureGLVertex *p; CoglTextureGLVertex *p;
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -2230,13 +2413,9 @@ cogl_texture_polygon (CoglHandle handle,
ctx->texture_vertices_size = nsize; ctx->texture_vertices_size = nsize;
if (ctx->texture_vertices) ctx->texture_vertices = g_realloc (ctx->texture_vertices,
ctx->texture_vertices = g_realloc (ctx->texture_vertices, nsize
nsize * sizeof (CoglTextureGLVertex));
* sizeof (CoglTextureGLVertex));
else
ctx->texture_vertices = g_malloc (nsize
* sizeof (CoglTextureGLVertex));
} }
/* Prepare GL state */ /* Prepare GL state */
@ -2249,7 +2428,7 @@ cogl_texture_polygon (CoglHandle handle,
else if (use_color) else if (use_color)
{ {
for (i = 0; i < n_vertices; i++) for (i = 0; i < n_vertices; i++)
if (vertices[i].color.alpha < 255) if (cogl_color_get_alpha_byte(&vertices[i].color) < 255)
{ {
enable_flags |= COGL_ENABLE_BLEND; enable_flags |= COGL_ENABLE_BLEND;
break; break;
@ -2264,14 +2443,14 @@ cogl_texture_polygon (CoglHandle handle,
if (use_color) if (use_color)
{ {
enable_flags |= COGL_ENABLE_COLOR_ARRAY; enable_flags |= COGL_ENABLE_COLOR_ARRAY;
GE( cogl_wrap_glColorPointer (4, GL_FIXED, sizeof (CoglTextureGLVertex), GE( glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].c) ); ctx->texture_vertices[0].c) );
} }
GE( cogl_wrap_glVertexPointer (3, GL_FIXED, sizeof (CoglTextureGLVertex), GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].v) ); ctx->texture_vertices[0].v) );
GE( cogl_wrap_glTexCoordPointer (2, GL_FIXED, sizeof (CoglTextureGLVertex), GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].t) ); ctx->texture_vertices[0].t) );
cogl_enable (enable_flags); cogl_enable (enable_flags);
@ -2279,25 +2458,31 @@ cogl_texture_polygon (CoglHandle handle,
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
/* Convert the vertices into an array of GLfixeds ready to pass to /* Convert the vertices into an array of GLfloats ready to pass to
OpenGL */ OpenGL */
for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++) for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++)
{ {
p->v[0] = vertices[i].x; #define CFX_F COGL_FIXED_TO_FLOAT
p->v[1] = vertices[i].y;
p->v[2] = vertices[i].z; p->v[0] = CFX_F(vertices[i].x);
p->t[0] = vertices[i].tx * (x_span->size - x_span->waste) / x_span->size; p->v[1] = CFX_F(vertices[i].y);
p->t[1] = vertices[i].ty * (y_span->size - y_span->waste) / y_span->size; p->v[2] = CFX_F(vertices[i].z);
p->c[0] = (vertices[i].color.red << 16) / 0xff; p->t[0] = CFX_F(vertices[i].tx
p->c[1] = (vertices[i].color.green << 16) / 0xff; * (x_span->size - x_span->waste) / x_span->size);
p->c[2] = (vertices[i].color.blue << 16) / 0xff; p->t[1] = CFX_F(vertices[i].ty
p->c[3] = (vertices[i].color.alpha << 16) / 0xff; * (y_span->size - y_span->waste) / y_span->size);
p->c[0] = cogl_color_get_red_byte(&vertices[i].color);
p->c[1] = cogl_color_get_green_byte(&vertices[i].color);
p->c[2] = cogl_color_get_blue_byte(&vertices[i].color);
p->c[3] = cogl_color_get_alpha_byte(&vertices[i].color);
#undef CFX_F
} }
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
/* Set the last color so that the cache of the alpha value will work /* Set the last color so that the cache of the alpha value will work
properly */ properly */