From 4514d49dda70b9b5a1833c7809dc4d22b1bcd3cd Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 3 Dec 2010 17:46:16 +0000 Subject: [PATCH] cogl-vertex-attribute: Use glVertexAttribPointer on GLES2 When the GLES2 wrapper is removed we can't use the fixed function API such as glColorPointer to set the builtin attributes. Instead the GLSL progend now maintains a cache of attribute locations that are queried with glGetAttribLocation. The code that previously maintained a cache of the enabled texture coord arrays has been modified to also cache the enabled vertex attributes under GLES2. The vertex attribute API is now the only place that is using this cache so it has been moved into cogl-vertex-attribute.c --- clutter/cogl/cogl/cogl-bitmask.c | 16 +- clutter/cogl/cogl/cogl-bitmask.h | 10 +- clutter/cogl/cogl/cogl-context.c | 8 +- clutter/cogl/cogl/cogl-context.h | 8 +- clutter/cogl/cogl/cogl-internal.h | 6 - clutter/cogl/cogl/cogl-pipeline-opengl.c | 30 +- .../cogl/cogl-pipeline-progend-glsl-private.h | 18 + .../cogl/cogl/cogl-pipeline-progend-glsl.c | 139 ++++++++ .../cogl/cogl/cogl-vertex-attribute-private.h | 3 + clutter/cogl/cogl/cogl-vertex-attribute.c | 319 +++++++++++++----- clutter/cogl/cogl/cogl.c | 36 +- 11 files changed, 455 insertions(+), 138 deletions(-) diff --git a/clutter/cogl/cogl/cogl-bitmask.c b/clutter/cogl/cogl/cogl-bitmask.c index f2ec22c51..568d549fa 100644 --- a/clutter/cogl/cogl/cogl-bitmask.c +++ b/clutter/cogl/cogl/cogl-bitmask.c @@ -172,8 +172,8 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, } void -_cogl_bitmask_clear_bits (CoglBitmask *dst, - const CoglBitmask *src) +_cogl_bitmask_xor_bits (CoglBitmask *dst, + const CoglBitmask *src) { if (_cogl_bitmask_has_array (src)) { @@ -190,8 +190,8 @@ _cogl_bitmask_clear_bits (CoglBitmask *dst, g_array_set_size (dst_array, src_array->len); for (i = 0; i < src_array->len; i++) - g_array_index (dst_array, unsigned int, i) &= - ~g_array_index (src_array, unsigned int, i); + g_array_index (dst_array, unsigned int, i) ^= + g_array_index (src_array, unsigned int, i); } else if (_cogl_bitmask_has_array (dst)) { @@ -199,12 +199,12 @@ _cogl_bitmask_clear_bits (CoglBitmask *dst, dst_array = (GArray *) *dst; - g_array_index (dst_array, unsigned int, 0) &= - ~(GPOINTER_TO_UINT (*src) >> 1); + g_array_index (dst_array, unsigned int, 0) ^= + (GPOINTER_TO_UINT (*src) >> 1); } else - *dst = GUINT_TO_POINTER ((GPOINTER_TO_UINT (*dst) & - ~GPOINTER_TO_UINT (*src)) | 1); + *dst = GUINT_TO_POINTER ((GPOINTER_TO_UINT (*dst) ^ + GPOINTER_TO_UINT (*src)) | 1); } void diff --git a/clutter/cogl/cogl/cogl-bitmask.h b/clutter/cogl/cogl/cogl-bitmask.h index 00e387261..e75f0947e 100644 --- a/clutter/cogl/cogl/cogl-bitmask.h +++ b/clutter/cogl/cogl/cogl-bitmask.h @@ -99,16 +99,16 @@ _cogl_bitmask_set_bits (CoglBitmask *dst, const CoglBitmask *src); /* - * cogl_bitmask_clear_bits: + * cogl_bitmask_xor_bits: * @dst: The bitmask to modify * @src: The bitmask to copy bits from * - * This makes sure that all of the bits that are set in @src are - * cleared in @dst. Any unset bits in @src are left alone in @dst. + * For every bit that is set in src, the corresponding bit in dst is + * inverted. */ void -_cogl_bitmask_clear_bits (CoglBitmask *dst, - const CoglBitmask *src); +_cogl_bitmask_xor_bits (CoglBitmask *dst, + const CoglBitmask *src); typedef void (* CoglBitmaskForeachFunc) (int bit_num, gpointer user_data); diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c index fc6000e2b..2b03fb05d 100644 --- a/clutter/cogl/cogl/cogl-context.c +++ b/clutter/cogl/cogl/cogl-context.c @@ -183,9 +183,9 @@ cogl_create_context (void) _context->pipeline1_nodes = g_array_sized_new (FALSE, FALSE, sizeof (CoglHandle), 20); - _cogl_bitmask_init (&_context->texcoord_arrays_enabled); + _cogl_bitmask_init (&_context->arrays_enabled); _cogl_bitmask_init (&_context->temp_bitmask); - _cogl_bitmask_init (&_context->texcoord_arrays_to_disable); + _cogl_bitmask_init (&_context->arrays_to_change); _context->max_texture_units = -1; _context->max_texture_image_units = -1; @@ -356,9 +356,9 @@ _cogl_destroy_context (void) if (_context->atlas) _cogl_atlas_free (_context->atlas); - _cogl_bitmask_destroy (&_context->texcoord_arrays_enabled); + _cogl_bitmask_destroy (&_context->arrays_enabled); _cogl_bitmask_destroy (&_context->temp_bitmask); - _cogl_bitmask_destroy (&_context->texcoord_arrays_to_disable); + _cogl_bitmask_destroy (&_context->arrays_to_change); g_slist_free (_context->texture_types); g_slist_free (_context->buffer_types); diff --git a/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h index 3e553b408..b26dfbcee 100644 --- a/clutter/cogl/cogl/cogl-context.h +++ b/clutter/cogl/cogl/cogl-context.h @@ -120,12 +120,14 @@ typedef struct GArray *pipeline0_nodes; GArray *pipeline1_nodes; - /* Bitmask of texture coordinates arrays that are enabled */ - CoglBitmask texcoord_arrays_enabled; + /* Bitmask of attributes enabled. On GLES2 these are the vertex + attribute numbers and on regular GL these are only used for the + texture coordinate arrays */ + CoglBitmask arrays_enabled; /* These are temporary bitmasks that are used when disabling texcoord arrays. They are here just to avoid allocating new ones each time */ - CoglBitmask texcoord_arrays_to_disable; + CoglBitmask arrays_to_change; CoglBitmask temp_bitmask; gboolean gl_blend_enable_cache; diff --git a/clutter/cogl/cogl/cogl-internal.h b/clutter/cogl/cogl/cogl-internal.h index 53637c274..a3e993612 100644 --- a/clutter/cogl/cogl/cogl-internal.h +++ b/clutter/cogl/cogl/cogl-internal.h @@ -115,12 +115,6 @@ _cogl_get_enable (void); void _cogl_flush_face_winding (void); -/* Disables the texcoord arrays that don't have a corresponding bit - set in the mask and sets ctx->texcoord_arrays_enabled to mask. Note - that it doesn't enable any extra texcoord arrays */ -void -_cogl_disable_other_texcoord_arrays (const CoglBitmask *mask); - void _cogl_transform_point (const CoglMatrix *matrix_mv, const CoglMatrix *matrix_p, diff --git a/clutter/cogl/cogl/cogl-pipeline-opengl.c b/clutter/cogl/cogl/cogl-pipeline-opengl.c index 83570c4e7..84ca8a51c 100644 --- a/clutter/cogl/cogl/cogl-pipeline-opengl.c +++ b/clutter/cogl/cogl/cogl-pipeline-opengl.c @@ -37,6 +37,11 @@ #include "cogl-context.h" #include "cogl-texture-private.h" +/* This is needed to set the color attribute on GLES2 */ +#ifdef HAVE_COGL_GLES2 +#include "cogl-pipeline-progend-glsl-private.h" +#endif + #include #include @@ -477,6 +482,8 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state ( { _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* On GLES2 we'll flush the color later */ +#ifndef HAVE_COGL_GLES2 if (!skip_gl_color) { if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) || @@ -492,6 +499,7 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state ( cogl_color_get_alpha_byte (&authority->color))); } } +#endif if (pipelines_difference & COGL_PIPELINE_STATE_BLEND) { @@ -1091,7 +1099,6 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, * 2) then foreach layer: * determine gl_target/gl_texture * bind texture - * flush user matrix * * Note: After _cogl_pipeline_flush_common_gl_state you can expect * all state of the layers corresponding texture unit to be @@ -1232,6 +1239,27 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, done: + /* We can't assume the color will be retained between flushes on + GLES2 because the generic attribute values are not stored as part + of the program object so they could be overridden by any + attribute changes in another program */ +#ifdef HAVE_COGL_GLES2 + if (!skip_gl_color) + { + int attribute; + CoglPipeline *authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); + + attribute = _cogl_pipeline_progend_glsl_get_color_attribute (pipeline); + if (attribute != -1) + GE (glVertexAttrib4f (attribute, + cogl_color_get_red_float (&authority->color), + cogl_color_get_green_float (&authority->color), + cogl_color_get_blue_float (&authority->color), + cogl_color_get_alpha_float (&authority->color))); + } +#endif + /* Handle the fact that OpenGL associates texture filter and wrap * modes with the texture objects not the texture units... */ foreach_texture_unit_update_filter_and_wrap_modes (); diff --git a/clutter/cogl/cogl/cogl-pipeline-progend-glsl-private.h b/clutter/cogl/cogl/cogl-pipeline-progend-glsl-private.h index 5dabc6684..6fe6e4bd4 100644 --- a/clutter/cogl/cogl/cogl-pipeline-progend-glsl-private.h +++ b/clutter/cogl/cogl/cogl-pipeline-progend-glsl-private.h @@ -29,8 +29,26 @@ #define __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H #include "cogl-pipeline-private.h" +#include "cogl-vertex-attribute-private.h" extern const CoglPipelineProgend _cogl_pipeline_glsl_progend; +#ifdef HAVE_COGL_GLES2 + +int +_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline); + +int +_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline); + +int +_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline); + +int +_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline, + int unit); + +#endif /* HAVE_COGL_GLES2 */ + #endif /* __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H */ diff --git a/clutter/cogl/cogl/cogl-pipeline-progend-glsl.c b/clutter/cogl/cogl/cogl-pipeline-progend-glsl.c index e0216b1f6..647e91954 100644 --- a/clutter/cogl/cogl/cogl-pipeline-progend-glsl.c +++ b/clutter/cogl/cogl/cogl-pipeline-progend-glsl.c @@ -94,6 +94,18 @@ typedef struct gboolean dirty_point_size; GLint point_size_uniform; + + /* Under GLES2 we can't use the builtin functions to set attribute + pointers such as the vertex position. Instead the vertex + attribute code needs to query the attribute numbers from the + progend backend */ + int position_attribute_location; + int color_attribute_location; + int normal_attribute_location; + int tex_coord0_attribute_location; + /* We only allocate this array if more than one tex coord attribute + is requested because most pipelines will only use one layer */ + GArray *tex_coord_attribute_locations; #endif /* We need to track the last pipeline that the program was used with @@ -125,6 +137,124 @@ get_glsl_priv (CoglPipeline *pipeline) return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key); } +#ifdef HAVE_COGL_GLES2 + +#define ATTRIBUTE_LOCATION_UNKNOWN -2 + +/* Under GLES2 the vertex attribute API needs to query the attribute + numbers because it can't used the fixed function API to set the + builtin attributes. We cache the attributes here because the + progend knows when the program is changed so it can clear the + cache. This should always be called after the pipeline is flushed + so they can assert that the gl program is valid */ + +int +_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline) +{ + CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); + + g_return_val_if_fail (priv != NULL, -1); + g_return_val_if_fail (priv->program != 0, -1); + + if (priv->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN) + GE_RET( priv->position_attribute_location, + glGetAttribLocation (priv->program, "cogl_position_in") ); + + return priv->position_attribute_location; +} + +int +_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline) +{ + CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); + + g_return_val_if_fail (priv != NULL, -1); + g_return_val_if_fail (priv->program != 0, -1); + + if (priv->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN) + GE_RET( priv->color_attribute_location, + glGetAttribLocation (priv->program, "cogl_color_in") ); + + return priv->color_attribute_location; +} + +int +_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline) +{ + CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); + + g_return_val_if_fail (priv != NULL, -1); + g_return_val_if_fail (priv->program != 0, -1); + + if (priv->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN) + GE_RET( priv->normal_attribute_location, + glGetAttribLocation (priv->program, "cogl_normal_in") ); + + return priv->normal_attribute_location; +} + +int +_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline, + int unit) +{ + CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); + + g_return_val_if_fail (priv != NULL, -1); + g_return_val_if_fail (priv->program != 0, -1); + + if (unit == 0) + { + if (priv->tex_coord0_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN) + GE_RET( priv->tex_coord0_attribute_location, + glGetAttribLocation (priv->program, "cogl_tex_coord0_in") ); + + return priv->tex_coord0_attribute_location; + } + else + { + char *name = g_strdup_printf ("cogl_tex_coord%i_in", unit); + int *locations; + + if (priv->tex_coord_attribute_locations == NULL) + priv->tex_coord_attribute_locations = g_array_new (FALSE, FALSE, + sizeof (int)); + if (priv->tex_coord_attribute_locations->len <= unit - 1) + { + int i = priv->tex_coord_attribute_locations->len; + g_array_set_size (priv->tex_coord_attribute_locations, unit); + for (; i < unit; i++) + g_array_index (priv->tex_coord_attribute_locations, int, i) = + ATTRIBUTE_LOCATION_UNKNOWN; + } + + locations = &g_array_index (priv->tex_coord_attribute_locations, int, 0); + + if (locations[unit - 1] == ATTRIBUTE_LOCATION_UNKNOWN) + GE_RET( locations[unit - 1], + glGetAttribLocation (priv->program, name) ); + + g_free (name); + + return locations[unit - 1]; + } +} + +static void +clear_attribute_cache (CoglPipelineProgendPrivate *priv) +{ + priv->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN; + priv->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN; + priv->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN; + priv->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN; + if (priv->tex_coord_attribute_locations) + { + g_array_free (priv->tex_coord_attribute_locations, TRUE); + priv->tex_coord_attribute_locations = NULL; + } +} + +#endif /* HAVE_COGL_GLES2 */ + static void destroy_glsl_priv (void *user_data) { @@ -132,6 +262,10 @@ destroy_glsl_priv (void *user_data) if (--priv->ref_count == 0) { +#ifdef HAVE_COGL_GLES2 + clear_attribute_cache (priv); +#endif + if (priv->program) delete_program (priv->program); @@ -360,6 +494,9 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, priv->n_tex_coord_attribs = 0; priv->unit_state = g_new (UnitState, cogl_pipeline_get_n_layers (pipeline)); +#ifdef HAVE_COGL_GLES2 + priv->tex_coord_attribute_locations = NULL; +#endif set_glsl_priv (authority, priv); } @@ -475,6 +612,8 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, #ifdef HAVE_COGL_GLES2 if (program_changed) { + clear_attribute_cache (priv); + GE_RET( priv->alpha_test_reference_uniform, glGetUniformLocation (gl_program, "_cogl_alpha_test_ref") ); diff --git a/clutter/cogl/cogl/cogl-vertex-attribute-private.h b/clutter/cogl/cogl/cogl-vertex-attribute-private.h index 9b0d6076b..1eaf6f0d6 100644 --- a/clutter/cogl/cogl/cogl-vertex-attribute-private.h +++ b/clutter/cogl/cogl/cogl-vertex-attribute-private.h @@ -76,5 +76,8 @@ _cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode, CoglIndices *indices, CoglVertexAttribute **attributes); +void +_cogl_vertex_attribute_disable_cached_arrays (void); + #endif /* __COGL_VERTEX_ATTRIBUTE_PRIVATE_H */ diff --git a/clutter/cogl/cogl/cogl-vertex-attribute.c b/clutter/cogl/cogl/cogl-vertex-attribute.c index 416c9b2bc..a6a126b2f 100644 --- a/clutter/cogl/cogl/cogl-vertex-attribute.c +++ b/clutter/cogl/cogl/cogl-vertex-attribute.c @@ -40,6 +40,9 @@ #include "cogl-texture-private.h" #include "cogl-framebuffer-private.h" #include "cogl-indices-private.h" +#ifdef HAVE_COGL_GLES2 +#include "cogl-pipeline-progend-glsl-private.h" +#endif #include #include @@ -423,6 +426,54 @@ validated: return status; } +static void +toggle_enabled_cb (int bit_num, void *user_data) +{ + const CoglBitmask *new_values = user_data; + gboolean enabled = _cogl_bitmask_get (new_values, bit_num); + +#ifdef HAVE_COGL_GLES2 + + if (enabled) + GE( glEnableVertexAttribArray (bit_num) ); + else + GE( glDisableVertexAttribArray (bit_num) ); + +#else /* HAVE_COGL_GLES2 */ + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + GE( glClientActiveTexture (GL_TEXTURE0 + bit_num) ); + + if (enabled) + GE( glEnableClientState (GL_TEXTURE_COORD_ARRAY) ); + else + GE( glDisableClientState (GL_TEXTURE_COORD_ARRAY) ); + +#endif /* HAVE_COGL_GLES2 */ +} + +static void +set_enabled_arrays (CoglBitmask *value_cache, + const CoglBitmask *new_values) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* Get the list of bits that are different */ + _cogl_bitmask_clear_all (&ctx->arrays_to_change); + _cogl_bitmask_set_bits (&ctx->arrays_to_change, value_cache); + _cogl_bitmask_xor_bits (&ctx->arrays_to_change, new_values); + + /* Iterate over each bit to change */ + _cogl_bitmask_foreach (&ctx->arrays_to_change, + toggle_enabled_cb, + (void *) new_values); + + /* Store the new values */ + _cogl_bitmask_clear_all (value_cache); + _cogl_bitmask_set_bits (value_cache, new_values); +} + static CoglHandle enable_gl_state (CoglVertexAttribute **attributes, ValidateLayerState *state) @@ -441,89 +492,31 @@ enable_gl_state (CoglVertexAttribute **attributes, source = cogl_get_source (); - _cogl_bitmask_clear_all (&ctx->temp_bitmask); - + /* Iterate the attributes to work out whether blending needs to be + enabled and how many texture coords there are. We need to do this + before flushing the pipeline. */ for (i = 0; attributes[i]; i++) - { - CoglVertexAttribute *attribute = attributes[i]; - CoglVertexArray *vertex_array; - CoglBuffer *buffer; - void *base; - - vertex_array = cogl_vertex_attribute_get_array (attribute); - buffer = COGL_BUFFER (vertex_array); - base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY); - - switch (attribute->name_id) - { - case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY: - enable_flags |= COGL_ENABLE_COLOR_ARRAY; - /* GE (glEnableClientState (GL_COLOR_ARRAY)); */ - GE (glColorPointer (attribute->n_components, - attribute->type, - attribute->stride, - base + attribute->offset)); - - if (!_cogl_pipeline_get_real_blend_enabled (source)) - { - CoglPipelineBlendEnable blend_enable = - COGL_PIPELINE_BLEND_ENABLE_ENABLED; - copy = cogl_pipeline_copy (source); - _cogl_pipeline_set_blend_enabled (copy, blend_enable); - source = copy; - } - skip_gl_color = TRUE; - break; - case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: - /* FIXME: go through cogl cache to enable normal array */ - GE (glEnableClientState (GL_NORMAL_ARRAY)); - GE (glNormalPointer (attribute->type, - attribute->stride, - base + attribute->offset)); - break; - case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: - GE (glClientActiveTexture (GL_TEXTURE0 + - attribute->texture_unit)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - GE (glTexCoordPointer (attribute->n_components, - attribute->type, - attribute->stride, - base + attribute->offset)); - _cogl_bitmask_set (&ctx->temp_bitmask, - attribute->texture_unit, TRUE); - n_tex_coord_attribs++; - break; - case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY: - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - /* GE (glEnableClientState (GL_VERTEX_ARRAY)); */ - GE (glVertexPointer (attribute->n_components, - attribute->type, - attribute->stride, - base + attribute->offset)); - break; - case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: + switch (attributes[i]->name_id) + { + case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY: + if (!_cogl_pipeline_get_real_blend_enabled (source)) { -#ifdef MAY_HAVE_PROGRAMABLE_GL - /* FIXME: go through cogl cache to enable generic array */ - GE (glEnableVertexAttribArray (generic_index++)); - GE (glVertexAttribPointer (generic_index, - attribute->n_components, - attribute->type, - attribute->normalized, - attribute->stride, - base + attribute->offset)); -#endif + CoglPipelineBlendEnable blend_enable = + COGL_PIPELINE_BLEND_ENABLE_ENABLED; + copy = cogl_pipeline_copy (source); + _cogl_pipeline_set_blend_enabled (copy, blend_enable); + source = copy; } - break; - default: - g_warning ("Unrecognised attribute type 0x%08x", attribute->type); - } + skip_gl_color = TRUE; + break; - _cogl_buffer_unbind (buffer); - } + case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: + n_tex_coord_attribs++; + break; - /* Disable any tex coord arrays that we didn't use */ - _cogl_disable_other_texcoord_arrays (&ctx->temp_bitmask); + default: + break; + } if (G_UNLIKELY (state->options.flags)) { @@ -585,12 +578,180 @@ enable_gl_state (CoglVertexAttribute **attributes, if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + _cogl_bitmask_clear_all (&ctx->temp_bitmask); + + /* Bind the attribute pointers. We need to do this after the + pipeline is flushed because on GLES2 that is the only point when + we can determine the attribute locations */ + + for (i = 0; attributes[i]; i++) + { + CoglVertexAttribute *attribute = attributes[i]; + CoglVertexArray *vertex_array; + CoglBuffer *buffer; + void *base; +#ifdef HAVE_COGL_GLES2 + int attrib_location; +#endif + + vertex_array = cogl_vertex_attribute_get_array (attribute); + buffer = COGL_BUFFER (vertex_array); + base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY); + + switch (attribute->name_id) + { + case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY: +#ifdef HAVE_COGL_GLES2 + + attrib_location = + _cogl_pipeline_progend_glsl_get_color_attribute (source); + if (attrib_location != -1) + { + GE( glVertexAttribPointer (attrib_location, + attribute->n_components, + attribute->type, + TRUE, /* normalize */ + attribute->stride, + base + attribute->offset) ); + + _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE); + } + +#else + + enable_flags |= COGL_ENABLE_COLOR_ARRAY; + /* GE (glEnableClientState (GL_COLOR_ARRAY)); */ + GE (glColorPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + +#endif + + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: +#ifdef HAVE_COGL_GLES2 + + attrib_location = + _cogl_pipeline_progend_glsl_get_normal_attribute (source); + if (attrib_location != -1) + { + GE( glVertexAttribPointer (attrib_location, + attribute->n_components, + attribute->type, + TRUE, /* normalize */ + attribute->stride, + base + attribute->offset) ); + _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE); + } + +#else + + /* FIXME: go through cogl cache to enable normal array */ + GE (glEnableClientState (GL_NORMAL_ARRAY)); + GE (glNormalPointer (attribute->type, + attribute->stride, + base + attribute->offset)); + +#endif + + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: +#ifdef HAVE_COGL_GLES2 + + attrib_location = _cogl_pipeline_progend_glsl_get_tex_coord_attribute + (source, attribute->texture_unit); + if (attrib_location != -1) + { + GE( glVertexAttribPointer (attrib_location, + attribute->n_components, + attribute->type, + FALSE, /* normalize */ + attribute->stride, + base + attribute->offset) ); + _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE); + } +#else + + GE (glClientActiveTexture (GL_TEXTURE0 + + attribute->texture_unit)); + GE (glTexCoordPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + _cogl_bitmask_set (&ctx->temp_bitmask, + attribute->texture_unit, TRUE); + +#endif + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY: +#ifdef HAVE_COGL_GLES2 + + attrib_location = + _cogl_pipeline_progend_glsl_get_position_attribute (source); + if (attrib_location != -1) + { + GE( glVertexAttribPointer (attrib_location, + attribute->n_components, + attribute->type, + FALSE, /* normalize */ + attribute->stride, + base + attribute->offset) ); + _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE); + } + +#else + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + /* GE (glEnableClientState (GL_VERTEX_ARRAY)); */ + GE (glVertexPointer (attribute->n_components, + attribute->type, + attribute->stride, + base + attribute->offset)); + +#endif + break; + case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: + { +#ifdef MAY_HAVE_PROGRAMABLE_GL + /* FIXME: go through cogl cache to enable generic array. */ + /* FIXME: this is going to end up just using the builtins + on GLES 2 */ + GE (glEnableVertexAttribArray (generic_index++)); + GE (glVertexAttribPointer (generic_index, + attribute->n_components, + attribute->type, + attribute->normalized, + attribute->stride, + base + attribute->offset)); +#endif + } + break; + default: + g_warning ("Unrecognised attribute type 0x%08x", attribute->type); + } + + _cogl_buffer_unbind (buffer); + } + + /* Flush the state of the attribute arrays */ + set_enabled_arrays (&ctx->arrays_enabled, &ctx->temp_bitmask); + _cogl_enable (enable_flags); _cogl_flush_face_winding (); return source; } +void +_cogl_vertex_attribute_disable_cached_arrays (void) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + _cogl_bitmask_clear_all (&ctx->temp_bitmask); + set_enabled_arrays (&ctx->arrays_enabled, &ctx->temp_bitmask); +} + /* FIXME: we shouldn't be disabling state after drawing we should * just disable the things not needed after enabling state. */ static void @@ -618,7 +779,9 @@ disable_gl_state (CoglVertexAttribute **attributes, break; case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: /* FIXME: go through cogl cache to enable normal array */ +#ifndef HAVE_COGL_GLES2 GE (glDisableClientState (GL_NORMAL_ARRAY)); +#endif break; case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: /* The enabled state of the texture coord arrays is diff --git a/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c index 5df6e93dc..13b35b415 100644 --- a/clutter/cogl/cogl/cogl.c +++ b/clutter/cogl/cogl/cogl.c @@ -45,6 +45,7 @@ #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-texture-driver.h" +#include "cogl-vertex-attribute-private.h" #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) #include "cogl-gles2-wrapper.h" @@ -702,36 +703,6 @@ cogl_read_pixels (int x, _cogl_get_format_bpp (format) * width); } -static void -_cogl_disable_other_texcoord_arrays_cb (int texcoord_array_num, gpointer data) -{ - CoglContext *ctx = data; - - GE (glClientActiveTexture (GL_TEXTURE0 + texcoord_array_num)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); -} - -void -_cogl_disable_other_texcoord_arrays (const CoglBitmask *mask) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* Set texcoord_arrays_to_disable to only contain the arrays we want - to disable */ - _cogl_bitmask_clear_all (&ctx->texcoord_arrays_to_disable); - _cogl_bitmask_set_bits (&ctx->texcoord_arrays_to_disable, - &ctx->texcoord_arrays_enabled); - _cogl_bitmask_clear_bits (&ctx->texcoord_arrays_to_disable, mask); - - _cogl_bitmask_foreach (&ctx->texcoord_arrays_to_disable, - _cogl_disable_other_texcoord_arrays_cb, ctx); - - /* Update the mask of arrays that are enabled */ - _cogl_bitmask_clear_bits (&ctx->texcoord_arrays_enabled, - &ctx->texcoord_arrays_to_disable); - _cogl_bitmask_set_bits (&ctx->texcoord_arrays_enabled, mask); -} - void cogl_begin_gl (void) { @@ -791,9 +762,8 @@ cogl_begin_gl (void) _cogl_enable (enable_flags); _cogl_flush_face_winding (); - /* Disable all client texture coordinate arrays */ - _cogl_bitmask_clear_all (&ctx->temp_bitmask); - _cogl_disable_other_texcoord_arrays (&ctx->temp_bitmask); + /* Disable any cached vertex arrays */ + _cogl_vertex_attribute_disable_cached_arrays (); } void