Support cogl_texture_multiple_rectangles in GL ES backend

This commit is contained in:
Neil Roberts 2008-12-09 15:10:33 +00:00
parent 59aef7488f
commit 223c1225ea
3 changed files with 212 additions and 156 deletions

View File

@ -59,9 +59,11 @@ cogl_create_context ()
_context->last_path = 0; _context->last_path = 0;
_context->texture_handles = NULL; _context->texture_handles = NULL;
_context->texture_vertices_size = 0; _context->texture_vertices = g_array_new (FALSE, FALSE,
_context->texture_vertices = NULL; sizeof (CoglTextureGLVertex));
_context->texture_indices = g_array_new (FALSE, FALSE,
sizeof (GLushort));
_context->fbo_handles = NULL; _context->fbo_handles = NULL;
_context->program_handles = NULL; _context->program_handles = NULL;
_context->shader_handles = NULL; _context->shader_handles = NULL;
@ -104,8 +106,10 @@ cogl_destroy_context ()
#endif #endif
if (_context->texture_vertices) if (_context->texture_vertices)
g_free (_context->texture_vertices); g_array_free (_context->texture_vertices, TRUE);
if (_context->texture_indices)
g_array_free (_context->texture_indices, TRUE);
if (_context->texture_handles) if (_context->texture_handles)
g_array_free (_context->texture_handles, TRUE); g_array_free (_context->texture_handles, TRUE);
if (_context->fbo_handles) if (_context->fbo_handles)

View File

@ -65,9 +65,14 @@ typedef struct
/* Textures */ /* Textures */
GArray *texture_handles; GArray *texture_handles;
CoglTextureGLVertex *texture_vertices; GArray *texture_vertices;
gulong texture_vertices_size; GArray *texture_indices;
/* The gl texture number that the above vertices apply to. This to
detect when a different slice is encountered so that the vertices
can be flushed */
GLuint texture_current;
GLenum texture_target;
/* Framebuffer objects */ /* Framebuffer objects */
GArray *fbo_handles; GArray *fbo_handles;
CoglBufferTarget draw_buffer; CoglBufferTarget draw_buffer;

View File

@ -2047,6 +2047,79 @@ cogl_texture_get_data (CoglHandle handle,
return byte_size; return byte_size;
} }
static void
_cogl_texture_flush_vertices (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->texture_vertices->len > 0)
{
CoglTextureGLVertex *p
= (CoglTextureGLVertex *) ctx->texture_vertices->data;
GE( glVertexPointer (2, GL_FLOAT,
sizeof (CoglTextureGLVertex), p->v ) );
GE( glTexCoordPointer (2, GL_FLOAT,
sizeof (CoglTextureGLVertex), p->t ) );
GE( glBindTexture (ctx->texture_target, ctx->texture_current) );
GE( glDrawElements (GL_TRIANGLES,
ctx->texture_indices->len,
GL_UNSIGNED_SHORT,
ctx->texture_indices->data) );
g_array_set_size (ctx->texture_vertices, 0);
g_array_set_size (ctx->texture_indices, 0);
}
}
static void
_cogl_texture_add_quad_vertices (GLfloat x1, GLfloat y1,
GLfloat x2, GLfloat y2,
GLfloat tx1, GLfloat ty1,
GLfloat tx2, GLfloat ty2)
{
CoglTextureGLVertex *p;
GLushort first_vert;
GLushort *q;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Add the four vertices of the quad to the list of queued
vertices */
first_vert = ctx->texture_vertices->len;
g_array_set_size (ctx->texture_vertices, first_vert + 4);
p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex, first_vert);
p->v[0] = x1; p->v[1] = y1;
p->t[0] = tx1; p->t[1] = ty1;
p++;
p->v[0] = x1; p->v[1] = y2;
p->t[0] = tx1; p->t[1] = ty2;
p++;
p->v[0] = x2; p->v[1] = y2;
p->t[0] = tx2; p->t[1] = ty2;
p++;
p->v[0] = x2; p->v[1] = y1;
p->t[0] = tx2; p->t[1] = ty1;
p++;
/* Add two triangles to the list of indices. That makes six new
indices but two of the vertices in the triangles are shared. */
g_array_set_size (ctx->texture_indices,
ctx->texture_indices->len + 6);
q = &g_array_index (ctx->texture_indices, GLushort,
ctx->texture_indices->len - 6);
*(q++) = first_vert + 0;
*(q++) = first_vert + 1;
*(q++) = first_vert + 3;
*(q++) = first_vert + 1;
*(q++) = first_vert + 2;
*(q++) = first_vert + 3;
}
static void static void
_cogl_texture_quad_sw (CoglTexture *tex, _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed x1, CoglFixed x1,
@ -2067,31 +2140,13 @@ _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;
GLfloat tex_coords[8];
GLfloat quad_coords[8];
GLuint gl_handle; 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);
#if COGL_DEBUG #if COGL_DEBUG
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif #endif
/* Prepare GL state */
if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT)
{
enable_flags |= COGL_ENABLE_BLEND;
}
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags);
/* If the texture coordinates are backwards then swap both the /* If the texture coordinates are backwards then swap both the
geometry and texture coordinates so that the texture will be geometry and texture coordinates so that the texture will be
@ -2115,10 +2170,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
ty1 = ty2; ty1 = ty2;
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);
@ -2158,17 +2210,16 @@ _cogl_texture_quad_sw (CoglTexture *tex,
slice_qy2 = first_qy + slice_qy2 = first_qy +
COGL_FIXED_MUL (iter_y.intersect_end - first_ty, tqy); COGL_FIXED_MUL (iter_y.intersect_end - first_ty, tqy);
/* Localize slice texture coordinates */ /* Localize slice texture coordinates */
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) */ (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;
/* Iterate until whole quad width covered */ /* Iterate until whole quad width covered */
for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans, for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
first_tx, tx1, tx2) ; first_tx, tx1, tx2) ;
@ -2188,12 +2239,12 @@ _cogl_texture_quad_sw (CoglTexture *tex,
/* Localize slice texture coordinates */ /* Localize slice texture coordinates */
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
(rectangle texture targets take denormalized) */ (rectangle texture targets take denormalized) */
slice_tx1 /= iter_x.span->size; slice_tx1 /= iter_x.span->size;
slice_tx2 /= 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);
printf("qx1: %f\n", COGL_FIXED_TO_FLOAT (slice_qx1)); printf("qx1: %f\n", COGL_FIXED_TO_FLOAT (slice_qx1));
@ -2210,26 +2261,23 @@ _cogl_texture_quad_sw (CoglTexture *tex,
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
iter_y.index * iter_x.array->len + iter_y.index * iter_x.array->len +
iter_x.index); iter_x.index);
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) );
#define CFX_F COGL_FIXED_TO_FLOAT /* If we're using a different texture from the one already queued
then flush the vertices */
/* Draw textured quad */ if (ctx->texture_vertices->len > 0
tex_coords[0] = CFX_F(slice_tx1); tex_coords[1] = CFX_F(slice_ty2); && gl_handle != ctx->texture_current)
tex_coords[2] = CFX_F(slice_tx2); tex_coords[3] = CFX_F(slice_ty2); _cogl_texture_flush_vertices ();
tex_coords[4] = CFX_F(slice_tx1); tex_coords[5] = CFX_F(slice_ty1); ctx->texture_target = tex->gl_target;
tex_coords[6] = CFX_F(slice_tx2); tex_coords[7] = CFX_F(slice_ty1); ctx->texture_current = gl_handle;
quad_coords[0] = CFX_F(slice_qx1); quad_coords[1] = CFX_F(slice_qy2); _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (slice_qx1),
quad_coords[2] = CFX_F(slice_qx2); quad_coords[3] = CFX_F(slice_qy2); COGL_FIXED_TO_FLOAT (slice_qy1),
quad_coords[4] = CFX_F(slice_qx1); quad_coords[5] = CFX_F(slice_qy1); COGL_FIXED_TO_FLOAT (slice_qx2),
quad_coords[6] = CFX_F(slice_qx2); quad_coords[7] = CFX_F(slice_qy1); COGL_FIXED_TO_FLOAT (slice_qy2),
COGL_FIXED_TO_FLOAT (slice_tx1),
GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); COGL_FIXED_TO_FLOAT (slice_ty1),
COGL_FIXED_TO_FLOAT (slice_tx2),
#undef CFX_F COGL_FIXED_TO_FLOAT (slice_ty2));
} }
} }
} }
@ -2245,41 +2293,27 @@ _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; GLuint gl_handle;
CoglTexSliceSpan *x_span; CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span; CoglTexSliceSpan *y_span;
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
| 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");
#endif #endif
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Prepare GL state */
if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT)
{
enable_flags |= COGL_ENABLE_BLEND;
}
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
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( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); /* If we're using a different texture from the one already queued
then flush the vertices */
if (ctx->texture_vertices->len > 0
&& gl_handle != ctx->texture_current)
_cogl_texture_flush_vertices ();
ctx->texture_target = tex->gl_target;
ctx->texture_current = gl_handle;
/* 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);
@ -2290,22 +2324,80 @@ _cogl_texture_quad_hw (CoglTexture *tex,
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) _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (x1),
COGL_FIXED_TO_FLOAT (y1),
COGL_FIXED_TO_FLOAT (x2),
COGL_FIXED_TO_FLOAT (y2),
COGL_FIXED_TO_FLOAT (tx1),
COGL_FIXED_TO_FLOAT (ty1),
COGL_FIXED_TO_FLOAT (tx2),
COGL_FIXED_TO_FLOAT (ty2));
}
void
cogl_texture_multiple_rectangles (CoglHandle handle,
const CoglFixed *verts,
guint n_rects)
{
CoglTexture *tex;
gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY
| COGL_ENABLE_TEXTURE_2D);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Check if valid texture */
if (!cogl_is_texture (handle))
return;
/* Draw textured quad */ cogl_clip_ensure ();
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);
quad_coords[0] = CFX_F(x1); quad_coords[1] = CFX_F(y2); tex = _cogl_texture_pointer_from_handle (handle);
quad_coords[2] = CFX_F(x2); quad_coords[3] = CFX_F(y2);
quad_coords[4] = CFX_F(x1); quad_coords[5] = CFX_F(y1); /* Make sure we got stuff to draw */
quad_coords[6] = CFX_F(x2); quad_coords[7] = CFX_F(y1); if (tex->slice_gl_handles == NULL)
return;
if (tex->slice_gl_handles->len == 0)
return;
GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); /* Prepare GL state */
if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT)
enable_flags |= COGL_ENABLE_BLEND;
#undef CFX_F if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags);
g_array_set_size (ctx->texture_vertices, 0);
while (n_rects-- > 0)
{
if (verts[4] != verts[6] && verts[5] != verts[7])
{
/* If there is only one GL texture and either the texture is
NPOT (no waste) or all of the coordinates are in the
range [0,1] then we can use hardware tiling */
if (tex->slice_gl_handles->len == 1
&& ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
&& tex->gl_target == GL_TEXTURE_2D)
|| (verts[4] >= 0 && verts[4] <= COGL_FIXED_1
&& verts[6] >= 0 && verts[6] <= COGL_FIXED_1
&& verts[5] >= 0 && verts[5] <= COGL_FIXED_1
&& verts[7] >= 0 && verts[7] <= COGL_FIXED_1)))
_cogl_texture_quad_hw (tex, verts[0],verts[1], verts[2],verts[3],
verts[4],verts[5], verts[6],verts[7]);
else
_cogl_texture_quad_sw (tex, verts[0],verts[1], verts[2],verts[3],
verts[4],verts[5], verts[6],verts[7]);
}
verts += 8;
}
_cogl_texture_flush_vertices ();
} }
void void
@ -2319,47 +2411,18 @@ cogl_texture_rectangle (CoglHandle handle,
CoglFixed tx2, CoglFixed tx2,
CoglFixed ty2) CoglFixed ty2)
{ {
CoglTexture *tex; CoglFixed verts[8];
/* Check if valid texture */
if (!cogl_is_texture (handle))
return;
cogl_clip_ensure (); verts[0] = x1;
verts[1] = y1;
tex = _cogl_texture_pointer_from_handle (handle); verts[2] = x2;
verts[3] = y2;
/* Make sure we got stuff to draw */ verts[4] = tx1;
if (tex->slice_gl_handles == NULL) verts[5] = ty1;
return; verts[6] = tx2;
verts[7] = ty2;
if (tex->slice_gl_handles->len == 0)
return; cogl_texture_multiple_rectangles (handle, verts, 1);
if (tx1 == tx2 || ty1 == ty2)
return;
/* Pick tiling mode according to hw support */
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
&& tex->slice_gl_handles->len == 1)
{
_cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
}
else
{
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);
}
}
} }
void void
@ -2405,23 +2468,9 @@ cogl_texture_polygon (CoglHandle handle,
/* Make sure there is enough space in the global texture vertex /* Make sure there is enough space in the global texture vertex
array. This is used so we can render the polygon with a single array. This is used so we can render the polygon with a single
call to OpenGL but still support any number of vertices */ call to OpenGL but still support any number of vertices */
if (ctx->texture_vertices_size < n_vertices) g_array_set_size (ctx->texture_vertices, n_vertices);
{ p = (CoglTextureGLVertex *) ctx->texture_vertices->data;
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 enable_flags = (COGL_ENABLE_TEXTURE_2D
| COGL_ENABLE_VERTEX_ARRAY | COGL_ENABLE_VERTEX_ARRAY
@ -2447,14 +2496,12 @@ cogl_texture_polygon (CoglHandle handle,
if (use_color) if (use_color)
{ {
enable_flags |= COGL_ENABLE_COLOR_ARRAY; enable_flags |= COGL_ENABLE_COLOR_ARRAY;
GE( glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (CoglTextureGLVertex), GE( glColorPointer (4, GL_UNSIGNED_BYTE,
ctx->texture_vertices[0].c) ); sizeof (CoglTextureGLVertex), p->c) );
} }
GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), p->v ) );
ctx->texture_vertices[0].v) ); GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) );
GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex),
ctx->texture_vertices[0].t) );
cogl_enable (enable_flags); cogl_enable (enable_flags);
@ -2464,7 +2511,7 @@ cogl_texture_polygon (CoglHandle handle,
/* Convert the vertices into an array of GLfloats 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; i < n_vertices; i++, p++)
{ {
#define CFX_F COGL_FIXED_TO_FLOAT #define CFX_F COGL_FIXED_TO_FLOAT