diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 7a56a9ada..1c306e16f 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -239,7 +239,7 @@ cogl_create_context (void) default_texture_data); cogl_push_source (_context->opaque_color_pipeline); - _cogl_pipeline_flush_gl_state (_context->opaque_color_pipeline, FALSE); + _cogl_pipeline_flush_gl_state (_context->opaque_color_pipeline, FALSE, 0); _cogl_enable (enable_flags); _cogl_flush_face_winding (); diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c index 9e4eee71a..0577f417b 100644 --- a/cogl/cogl-path.c +++ b/cogl/cogl-path.c @@ -230,7 +230,7 @@ _cogl_path_stroke_nodes (void) cogl_push_source (source); - _cogl_pipeline_flush_gl_state (source, FALSE); + _cogl_pipeline_flush_gl_state (source, FALSE, 0); /* Disable all client texture coordinate arrays */ _cogl_bitmask_clear_all (&ctx->temp_bitmask); @@ -376,7 +376,7 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path, /* Just setup a simple pipeline that doesn't use texturing... */ cogl_push_source (ctx->stencil_pipeline); - _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE); + _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE, 0); _cogl_enable (enable_flags); diff --git a/cogl/cogl-pipeline-arbfp.c b/cogl/cogl-pipeline-arbfp.c index dea031c98..97b5e3693 100644 --- a/cogl/cogl-pipeline-arbfp.c +++ b/cogl/cogl-pipeline-arbfp.c @@ -327,7 +327,8 @@ get_arbfp_program_state (CoglPipeline *pipeline) static gboolean _cogl_pipeline_backend_arbfp_start (CoglPipeline *pipeline, int n_layers, - unsigned long pipelines_difference) + unsigned long pipelines_difference, + int n_tex_coord_attribs) { CoglPipelineBackendARBfpPrivate *priv; CoglPipeline *authority; diff --git a/cogl/cogl-pipeline-fixed.c b/cogl/cogl-pipeline-fixed.c index 092e5cccd..11337b7bd 100644 --- a/cogl/cogl-pipeline-fixed.c +++ b/cogl/cogl-pipeline-fixed.c @@ -73,7 +73,8 @@ _cogl_pipeline_backend_fixed_get_max_texture_units (void) static gboolean _cogl_pipeline_backend_fixed_start (CoglPipeline *pipeline, int n_layers, - unsigned long pipelines_difference) + unsigned long pipelines_difference, + int n_tex_coord_attribs) { _cogl_use_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED); return TRUE; diff --git a/cogl/cogl-pipeline-glsl.c b/cogl/cogl-pipeline-glsl.c index 3e322e2f3..c94e517bf 100644 --- a/cogl/cogl-pipeline-glsl.c +++ b/cogl/cogl-pipeline-glsl.c @@ -73,6 +73,17 @@ typedef struct _GlslProgramState unsigned int user_program_age; GLuint gl_program; +#ifdef HAVE_COGL_GLES2 + /* To allow writing shaders that are portable between GLES 2 and + * OpenGL Cogl prepends a number of boilerplate #defines and + * declarations to user shaders. One of those declarations is an + * array of texture coordinate varyings, but to know how to emit the + * declaration we need to know how many texture coordinate + * attributes are in use. The boilerplate also needs to be changed + * if this increases. */ + int n_tex_coord_attribs; +#endif + /* This is set to TRUE if the program has changed since we last flushed the uniforms */ gboolean gl_program_changed; @@ -252,7 +263,8 @@ link_program (GLint gl_program) static gboolean _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline, int n_layers, - unsigned long pipelines_difference) + unsigned long pipelines_difference, + int n_tex_coord_attribs) { CoglPipelineBackendGlslPrivate *priv; CoglPipeline *authority; @@ -285,8 +297,17 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline, if (priv->glsl_program_state) { /* However if the program has changed since the last link then we do - need to relink */ - if (priv->glsl_program_state->user_program_age == user_program->age) + * need to relink + * + * Also if the number of texture coordinate attributes in use has + * increased, then delete the program so we can prepend a new + * _cogl_tex_coord[] varying array declaration. */ + if (priv->glsl_program_state->user_program_age == user_program->age +#ifdef HAVE_COGL_GLES2 + && priv->glsl_program_state->n_tex_coord_attribs >= + n_tex_coord_attribs +#endif + ) return TRUE; /* Destroy the existing program. We can't just dirty the whole @@ -340,6 +361,18 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline, GE_RET( gl_program, glCreateProgram () ); +#ifdef HAVE_COGL_GLES2 + /* Find the largest count of texture coordinate attributes + * associated with each of the shaders so we can ensure a consistent + * _cogl_tex_coord[] array declaration across all of the shaders.*/ + for (l = user_program->attached_shaders; l; l = l->next) + { + CoglShader *shader = l->data; + n_tex_coord_attribs = MAX (shader->n_tex_coord_attribs, + n_tex_coord_attribs); + } +#endif + /* Add all of the shaders from the user program */ for (l = user_program->attached_shaders; l; l = l->next) { @@ -347,11 +380,16 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline, g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL); + _cogl_shader_compile_real (shader, n_tex_coord_attribs); + GE( glAttachShader (gl_program, shader->gl_handle) ); } priv->glsl_program_state->gl_program = gl_program; priv->glsl_program_state->user_program_age = user_program->age; +#ifdef HAVE_COGL_GLES2 + priv->glsl_program_state->n_tex_coord_attribs = n_tex_coord_attribs; +#endif link_program (gl_program); diff --git a/cogl/cogl-pipeline-opengl-private.h b/cogl/cogl-pipeline-opengl-private.h index 21bf0c5e9..43917b12a 100644 --- a/cogl/cogl-pipeline-opengl-private.h +++ b/cogl/cogl-pipeline-opengl-private.h @@ -150,7 +150,8 @@ _cogl_gl_use_program_wrapper (CoglHandle program); void _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, - gboolean skip_gl_state); + gboolean skip_gl_state, + int n_tex_coord_attribs); #endif /* __COGL_PIPELINE_OPENGL_PRIVATE_H */ diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c index 7c2d1d77b..9a69b38e7 100644 --- a/cogl/cogl-pipeline-opengl.c +++ b/cogl/cogl-pipeline-opengl.c @@ -1036,7 +1036,8 @@ backend_add_layer_cb (CoglPipelineLayer *layer, */ void _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, - gboolean skip_gl_color) + gboolean skip_gl_color, + int n_tex_coord_attribs) { unsigned long pipelines_difference; int n_layers; @@ -1139,7 +1140,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, * scratch buffers here... */ if (G_UNLIKELY (!backend->start (pipeline, n_layers, - pipelines_difference))) + pipelines_difference, + n_tex_coord_attribs))) continue; state.backend = backend; diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h index 955c3d767..b14669706 100644 --- a/cogl/cogl-pipeline-private.h +++ b/cogl/cogl-pipeline-private.h @@ -552,7 +552,8 @@ typedef struct _CoglPipelineBackend gboolean (*start) (CoglPipeline *pipeline, int n_layers, - unsigned long pipelines_difference); + unsigned long pipelines_difference, + int n_tex_coord_attribs); gboolean (*add_layer) (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference); diff --git a/cogl/cogl-shader-boilerplate.h b/cogl/cogl-shader-boilerplate.h new file mode 100644 index 000000000..1ed3519e2 --- /dev/null +++ b/cogl/cogl-shader-boilerplate.h @@ -0,0 +1,107 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * Authors: + * Robert Bragg + */ + +#ifndef __COGL_SHADER_BOILERPLATE_H +#define __COGL_SHADER_BOILERPLATE_H + +#include "cogl.h" + + +#define _COGL_COMMON_SHADER_BOILERPLATE \ + "#define COGL_VERSION 100\n" \ + "\n" + +#ifndef HAVE_COGL_GLES2 + +#define _COGL_VERTEX_SHADER_BOILERPLATE \ + _COGL_COMMON_SHADER_BOILERPLATE \ + "#define cogl_position_in gl_Vertex\n" \ + "#define cogl_color_in gl_Color\n" \ + "#define cogl_tex_coord_in gl_MultiTexCoord0\n" \ + "#define cogl_tex_coord0_in gl_MultiTexCoord0\n" \ + "#define cogl_tex_coord1_in gl_MultiTexCoord1\n" \ + "#define cogl_tex_coord2_in gl_MultiTexCoord2\n" \ + "#define cogl_tex_coord3_in gl_MultiTexCoord3\n" \ + "#define cogl_tex_coord4_in gl_MultiTexCoord4\n" \ + "#define cogl_tex_coord5_in gl_MultiTexCoord5\n" \ + "#define cogl_tex_coord6_in gl_MultiTexCoord6\n" \ + "#define cogl_tex_coord7_in gl_MultiTexCoord7\n" \ + "#define cogl_normal_in gl_Normal\n" \ + "\n" \ + "#define cogl_position_out gl_Position\n" \ + "#define cogl_point_size_out gl_PointSize\n" \ + "#define cogl_color_out gl_FrontColor\n" \ + "#define cogl_tex_coord_out gl_TexCoord\n" \ + "\n" \ + "#define cogl_modelview_matrix gl_ModelViewMatrix\n" \ + "#define cogl_modelview_projection_matrix gl_ModelViewProjectionMatrix\n" \ + "#define cogl_projection_matrix gl_ProjectionMatrix\n" \ + "#define cogl_texture_matrix gl_TextureMatrix\n" \ + +#define _COGL_FRAGMENT_SHADER_BOILERPLATE \ + _COGL_COMMON_SHADER_BOILERPLATE \ + "#define cogl_color_in gl_Color\n" \ + "#define cogl_tex_coord_in gl_TexCoord\n" \ + "\n" \ + "#define cogl_color_out gl_FragColor\n" \ + "#define cogl_depth_out gl_FragDepth\n" \ + "\n" \ + "#define cogl_front_facing gl_FrontFacing\n" +#if 0 + /* GLSL 1.2 has a bottom left origin, though later versions + * allow use of an origin_upper_left keyword which would be + * more appropriate for Cogl. */ + "#define coglFragCoord gl_FragCoord\n" +#endif + +#else /* HAVE_COGL_GLES2 */ + +#define _COGL_VERTEX_SHADER_BOILERPLATE \ + _COGL_COMMON_SHADER_BOILERPLATE \ + "#define cogl_color_out _cogl_color\n" \ + "#define cogl_point_coord_out _cogl_point_coord\n" \ + "#define cogl_tex_coord_out _cogl_tex_coord\n" + +#define _COGL_FRAGMENT_SHADER_BOILERPLATE \ + _COGL_COMMON_SHADER_BOILERPLATE \ + "#if __VERSION__ == 100\n" \ + "precision highp float;\n" \ + "#endif\n" \ + "\n" \ + "varying vec4 _cogl_color;\n" \ + "\n" \ + "#define cogl_color_in _cogl_color\n" \ + "#define cogl_tex_coord_in _cogl_tex_coord\n" \ + "\n" \ + "#define cogl_color_out gl_FragColor\n" \ + "#define cogl_depth_out gl_FragDepth\n" \ + "\n" \ + "#define cogl_front_facing gl_FrontFacing\n" + +#endif /* HAVE_COGL_GLES2 */ + +#endif /* __COGL_SHADER_BOILERPLATE_H */ + diff --git a/cogl/cogl-shader-private.h b/cogl/cogl-shader-private.h index 9ba448002..03269a570 100644 --- a/cogl/cogl-shader-private.h +++ b/cogl/cogl-shader-private.h @@ -40,12 +40,17 @@ struct _CoglShader { CoglHandleObject _parent; GLuint gl_handle; + int n_tex_coord_attribs; CoglShaderType type; CoglShaderLanguage language; + char *source; }; CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle); +void +_cogl_shader_compile_real (CoglHandle handle, int n_tex_coord_attribs); + CoglShaderLanguage _cogl_program_get_language (CoglHandle handle); diff --git a/cogl/cogl-shader.c b/cogl/cogl-shader.c index 6391ea529..b58cbe686 100644 --- a/cogl/cogl-shader.c +++ b/cogl/cogl-shader.c @@ -27,6 +27,7 @@ #include "cogl.h" #include "cogl-shader-private.h" +#include "cogl-shader-boilerplate.h" #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -100,11 +101,35 @@ cogl_create_shader (CoglShaderType type) shader = g_slice_new (CoglShader); shader->language = COGL_SHADER_LANGUAGE_GLSL; shader->gl_handle = 0; +#ifdef HAVE_COGL_GLES2 + shader->n_tex_coord_attribs = 0; +#endif shader->type = type; return _cogl_shader_handle_new (shader); } +static void +delete_shader (CoglShader *shader) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + +#ifdef HAVE_COGL_GL + if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) + { + if (shader->gl_handle) + GE (glDeletePrograms (1, &shader->gl_handle)); + } + else +#endif + { + if (shader->gl_handle) + GE (glDeleteShader (shader->gl_handle)); + } + + shader->gl_handle = 0; +} + void cogl_shader_source (CoglHandle handle, const char *source) @@ -127,29 +152,55 @@ cogl_shader_source (CoglHandle handle, language = COGL_SHADER_LANGUAGE_GLSL; /* Delete the old object if the language is changing... */ - if (G_UNLIKELY (language != shader->language)) - { -#ifdef HAVE_COGL_GL - if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) - { - if (shader->gl_handle) - GE (glDeletePrograms (1, &shader->gl_handle)); - } - else -#endif - { - if (shader->gl_handle) - GE (glDeleteShader (shader->gl_handle)); - } - } + if (G_UNLIKELY (language != shader->language) && + shader->gl_handle) + delete_shader (shader); + + shader->source = g_strdup (source); + + shader->language = language; +} + +void +cogl_shader_compile (CoglHandle handle) +{ + CoglShader *shader = handle; + + if (!cogl_is_shader (handle)) + return; #ifdef HAVE_COGL_GL - if (language == COGL_SHADER_LANGUAGE_ARBFP) + _cogl_shader_compile_real (shader, 0 /* ignored */); +#endif + + /* XXX: For GLES2 we don't actually compile anything until the + * shader gets used so we have an opportunity to add some + * boilerplate to the shader. + * + * At the end of the day this is obviously a badly designed API + * given that we are having to lie to the user. It was a mistake to + * so thinly wrap the OpenGL shader API and the current plan is to + * replace it with a pipeline snippets API. */ +} + +void +_cogl_shader_compile_real (CoglHandle handle, + int n_tex_coord_attribs) +{ + CoglShader *shader = handle; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + +#ifdef HAVE_COGL_GL + if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) { #ifdef COGL_GL_DEBUG GLenum gl_error; #endif + if (shader->gl_handle) + return; + GE (glGenPrograms (1, &shader->gl_handle)); GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle)); @@ -160,8 +211,8 @@ cogl_shader_source (CoglHandle handle, #endif glProgramString (GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen (source), - source); + strlen (shader->source), + shader->source); #ifdef COGL_GL_DEBUG gl_error = glGetError (); if (gl_error != GL_NO_ERROR) @@ -169,7 +220,7 @@ cogl_shader_source (CoglHandle handle, g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s", G_STRLOC, gl_error, - source, + shader->source, glGetString (GL_PROGRAM_ERROR_STRING_ARB)); } #endif @@ -177,44 +228,70 @@ cogl_shader_source (CoglHandle handle, else #endif { - if (!shader->gl_handle) + char *sourcev[4]; + int count = 0; + GLenum gl_type; + + if (shader->gl_handle +#ifdef HAVE_COGL_GLES2 + && shader->n_tex_coord_attribs >= n_tex_coord_attribs +#endif + ) + return; + + if (shader->gl_handle) + delete_shader (shader); + + switch (shader->type) { - GLenum gl_type; - - switch (shader->type) - { - case COGL_SHADER_TYPE_VERTEX: - gl_type = GL_VERTEX_SHADER; - break; - case COGL_SHADER_TYPE_FRAGMENT: - gl_type = GL_FRAGMENT_SHADER; - break; - default: - g_assert_not_reached (); - break; - } - - shader->gl_handle = glCreateShader (gl_type); + case COGL_SHADER_TYPE_VERTEX: + gl_type = GL_VERTEX_SHADER; + break; + case COGL_SHADER_TYPE_FRAGMENT: + gl_type = GL_FRAGMENT_SHADER; + break; + default: + g_assert_not_reached (); + break; } - glShaderSource (shader->gl_handle, 1, &source, NULL); + + shader->gl_handle = glCreateShader (gl_type); + + sourcev[count++] = _COGL_COMMON_SHADER_BOILERPLATE; + if (shader->type == COGL_SHADER_TYPE_VERTEX) + sourcev[count++] = _COGL_VERTEX_SHADER_BOILERPLATE; + else + sourcev[count++] = _COGL_FRAGMENT_SHADER_BOILERPLATE; + +#ifdef HAVE_COGL_GLES2 + if (n_tex_coord_attribs) + sourcev[count++] = + g_strdup_printf ("varying vec2 _cogl_tex_coord[%d];\n", + n_tex_coord_attribs); + shader->n_tex_coord_attribs = n_tex_coord_attribs; +#endif + + sourcev[count++] = shader->source; + + glShaderSource (shader->gl_handle, count, (const char **)sourcev, NULL); + +#ifdef HAVE_COGL_GLES2 + if (count == 4) + g_free (sourcev[2]); +#endif + + GE (glCompileShader (shader->gl_handle)); + +#ifdef COGL_GL_DEBUG + if (!cogl_shader_is_compiled (handle)) + { + char *log = cogl_shader_get_info_log (handle); + g_warning ("Failed to compile GLSL program:\nsrc:\n%s\nerror:\n%s\n", + shader->source, + log); + } +#endif } - - shader->language = language; -} - -void -cogl_shader_compile (CoglHandle handle) -{ - CoglShader *shader; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (!cogl_is_shader (handle)) - return; - - shader = _cogl_shader_pointer_from_handle (handle); - - if (shader->language == COGL_SHADER_LANGUAGE_GLSL) - GE (glCompileShader (shader->gl_handle)); } char * @@ -242,6 +319,21 @@ cogl_shader_get_info_log (CoglHandle handle) { char buffer[512]; int len = 0; + + /* We don't normally compile the shader when the user calls + * cogl_shader_compile() because we want to be able to add + * boilerplate code that depends on how it ends up finally being + * used. + * + * Here we force an early compile if the user is interested in + * log information to increase the chance that the log will be + * useful! We have to guess the number of texture coordinate + * attributes that may be used (normally less than 4) since that + * affects the boilerplate. + */ + if (!shader->gl_handle) + _cogl_shader_compile_real (handle, 4); + glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); buffer[len] = '\0'; return g_strdup (buffer); @@ -284,6 +376,24 @@ cogl_shader_is_compiled (CoglHandle handle) else #endif { + /* FIXME: We currently have an arbitrary limit of 4 texture + * coordinate attributes since our API means we have to add + * some boilerplate to the users GLSL program (for GLES2) + * before we actually know how many attributes are in use. + * + * 4 will probably be enough (or at least that limitation should + * be enough until we can replace this API with the pipeline + * snippets API) but if it isn't then the shader won't compile, + * through no fault of the user. + * + * To some extent this is just a symptom of bad API design; it + * was a mistake for Cogl to so thinly wrap the OpenGL shader + * API. Eventually we plan for this whole API will be deprecated + * by the pipeline snippets framework. + */ + if (!shader->gl_handle) + _cogl_shader_compile_real (handle, 4); + GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); if (status == GL_TRUE) return TRUE; diff --git a/cogl/cogl-vertex-attribute.c b/cogl/cogl-vertex-attribute.c index 2b5682e57..199354b9c 100644 --- a/cogl/cogl-vertex-attribute.c +++ b/cogl/cogl-vertex-attribute.c @@ -435,6 +435,7 @@ enable_gl_state (CoglVertexAttribute **attributes, gboolean skip_gl_color = FALSE; CoglPipeline *source; CoglPipeline *copy = NULL; + int n_tex_coord_attribs = 0; _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); @@ -490,6 +491,7 @@ enable_gl_state (CoglVertexAttribute **attributes, 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; @@ -578,7 +580,7 @@ enable_gl_state (CoglVertexAttribute **attributes, _cogl_pipeline_apply_legacy_state (source); } - _cogl_pipeline_flush_gl_state (source, skip_gl_color); + _cogl_pipeline_flush_gl_state (source, skip_gl_color, n_tex_coord_attribs); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; diff --git a/cogl/cogl-vertex-buffer.c b/cogl/cogl-vertex-buffer.c index 192d4d561..47ac93a37 100644 --- a/cogl/cogl-vertex-buffer.c +++ b/cogl/cogl-vertex-buffer.c @@ -218,6 +218,79 @@ validate_gl_attribute (const char *gl_attribute, return type; } +/* There are a number of standard OpenGL attributes that we deal with + * specially. These attributes are all namespaced with a "gl_" prefix + * so we should catch any typos instead of silently adding a custom + * attribute. + */ +static CoglVertexBufferAttribFlags +validate_cogl_attribute (const char *cogl_attribute, + guint8 n_components, + guint8 *texture_unit) +{ + CoglVertexBufferAttribFlags type; + char *detail_seperator = NULL; + int name_len; + + detail_seperator = strstr (cogl_attribute, "::"); + if (detail_seperator) + name_len = detail_seperator - cogl_attribute; + else + name_len = strlen (cogl_attribute); + + if (strncmp (cogl_attribute, "position_in", name_len) == 0) + { + if (G_UNLIKELY (n_components == 1)) + g_critical ("glVertexPointer doesn't allow 1 component vertex " + "positions so we currently only support " + "\"cogl_position_in\" attributes where " + "n_components == 2, 3 or 4"); + type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY; + } + else if (strncmp (cogl_attribute, "color_in", name_len) == 0) + { + if (G_UNLIKELY (n_components != 3 && n_components != 4)) + g_critical ("glColorPointer expects 3 or 4 component colors so we " + "currently only support \"cogl_color_in\" attributes " + "where n_components == 3 or 4"); + type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY; + } + else if (strncmp (cogl_attribute, + "cogl_tex_coord", + strlen ("cogl_tex_coord")) == 0) + { + unsigned int unit; + + if (strcmp (cogl_attribute, "cogl_tex_coord_in") == 0) + unit = 0; + else if (sscanf (cogl_attribute, "cogl_tex_coord%u_in", &unit) != 1) + { + g_warning ("texture coordinate attributes should either be " + "referenced as \"cogl_tex_coord_in\" or with a" + "texture unit number like \"cogl_tex_coord1_in\""); + unit = 0; + } + /* FIXME: validate any '::' delimiter for this case */ + *texture_unit = unit; + type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY; + } + else if (strncmp (cogl_attribute, "normal_in", name_len) == 0) + { + if (G_UNLIKELY (n_components != 3)) + g_critical ("glNormalPointer expects 3 component normals so we " + "currently only support \"cogl_normal_in\" attributes " + "where n_components == 3"); + type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY; + } + else + { + g_warning ("Unknown cogl_* attribute name cogl_%s\n", cogl_attribute); + type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID; + } + + return type; +} + /* This validates that a custom attribute name is a valid GLSL variable name * * NB: attribute names may have a detail component delimited using '::' E.g. @@ -402,8 +475,9 @@ cogl_vertex_buffer_add (CoglHandle handle, attribute = submitted_attribute; - /* since we will skip validate_gl_attribute in this case, we need - * to pluck out the attribute type before overwriting the flags: */ + /* since we will skip validate_gl/cogl_attribute in this case, we + * need to pluck out the attribute type before overwriting the + * flags: */ flags |= attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK; break; @@ -424,6 +498,14 @@ cogl_vertex_buffer_add (CoglHandle handle, if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) return; } + else if (strncmp (attribute_name, "cogl_", 5) == 0) + { + flags |= validate_cogl_attribute (attribute_name + 5, + n_components, + &texture_unit); + if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) + return; + } else { flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY; diff --git a/cogl/cogl.c b/cogl/cogl.c index e21b088b0..b1882ef80 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -745,6 +745,7 @@ void cogl_begin_gl (void) { unsigned long enable_flags = 0; + CoglPipeline *pipeline; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -777,8 +778,21 @@ cogl_begin_gl (void) * * A user should instead call cogl_set_source_color4ub() before * cogl_begin_gl() to simplify the state flushed. + * + * XXX: note defining n_tex_coord_attribs using + * cogl_pipeline_get_n_layers is a hack, but the problem is that + * n_tex_coord_attribs is usually defined when drawing a primitive + * which isn't happening here. + * + * Maybe it would be more useful if this code did flush the + * opaque_color_pipeline and then call into cogl-pipeline-opengl.c to then + * restore all state for the material's backend back to default OpenGL + * values. */ - _cogl_pipeline_flush_gl_state (cogl_get_source (), FALSE); + pipeline = cogl_get_source (); + _cogl_pipeline_flush_gl_state (pipeline, + FALSE, + cogl_pipeline_get_n_layers (pipeline)); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; diff --git a/cogl/driver/gles/cogl-fixed-fragment-shader.glsl b/cogl/driver/gles/cogl-fixed-fragment-shader.glsl index 3f82deebb..1facee71f 100644 --- a/cogl/driver/gles/cogl-fixed-fragment-shader.glsl +++ b/cogl/driver/gles/cogl-fixed-fragment-shader.glsl @@ -7,8 +7,8 @@ precision highp float; /*** _cogl_fixed_fragment_shader_inputs ***/ /* Inputs from the vertex shader */ -varying vec4 frag_color; -varying float fog_amount; +varying vec4 _cogl_color; +varying float _cogl_fog_amount; /*** _cogl_fixed_fragment_shader_texturing_options ***/ @@ -17,10 +17,10 @@ varying float fog_amount; /*** _cogl_fixed_fragment_shader_fogging_options ***/ /* Fogging options */ -uniform vec4 fog_color; +uniform vec4 _cogl_fog_color; /* Alpha test options */ -uniform float alpha_test_ref; +uniform float _cogl_alpha_test_ref; /*** _cogl_fixed_fragment_shader_main_declare ***/ @@ -33,30 +33,32 @@ main (void) /*** _cogl_fixed_fragment_shader_fog ***/ /* Mix the calculated color with the fog color */ - gl_FragColor.rgb = mix (fog_color.rgb, gl_FragColor.rgb, fog_amount); + gl_FragColor.rgb = mix (_cogl_fog_color.rgb, gl_FragColor.rgb, + _cogl_fog_amount); /* Alpha testing */ /*** _cogl_fixed_fragment_shader_alpha_never ***/ discard; /*** _cogl_fixed_fragment_shader_alpha_less ***/ - if (gl_FragColor.a >= alpha_test_ref) + if (gl_FragColor.a >= _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_alpha_equal ***/ - if (gl_FragColor.a != alpha_test_ref) + if (gl_FragColor.a != _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_alpha_lequal ***/ - if (gl_FragColor.a > alpha_test_ref) + if (gl_FragColor.a > _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_alpha_greater ***/ - if (gl_FragColor.a <= alpha_test_ref) + if (gl_FragColor.a <= _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_alpha_notequal ***/ - if (gl_FragColor.a == alpha_test_ref) + if (gl_FragColor.a == _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_alpha_gequal ***/ - if (gl_FragColor.a < alpha_test_ref) + if (gl_FragColor.a < _cogl_alpha_test_ref) discard; /*** _cogl_fixed_fragment_shader_end ***/ } + diff --git a/cogl/driver/gles/cogl-fixed-vertex-shader.glsl b/cogl/driver/gles/cogl-fixed-vertex-shader.glsl index 0080477d3..f73f8b9a8 100644 --- a/cogl/driver/gles/cogl-fixed-vertex-shader.glsl +++ b/cogl/driver/gles/cogl-fixed-vertex-shader.glsl @@ -1,30 +1,30 @@ /*** _cogl_fixed_vertex_shader_per_vertex_attribs ***/ /* Per vertex attributes */ -attribute vec4 vertex_attrib; -attribute vec4 color_attrib; +attribute vec4 cogl_position_in; +attribute vec4 cogl_color_in; /*** _cogl_fixed_vertex_shader_transform_matrices ***/ /* Transformation matrices */ -uniform mat4 modelview_matrix; -uniform mat4 mvp_matrix; /* combined modelview and projection matrix */ +uniform mat4 cogl_modelview_matrix; +uniform mat4 cogl_modelview_projection_matrix; /* combined modelview and projection matrix */ /*** _cogl_fixed_vertex_shader_output_variables ***/ /* Outputs to the fragment shader */ -varying vec4 frag_color; -varying float fog_amount; +varying vec4 _cogl_color; +varying float _cogl_fog_amount; /*** _cogl_fixed_vertex_shader_fogging_options ***/ /* Fogging options */ -uniform float fog_density; -uniform float fog_start; -uniform float fog_end; +uniform float _cogl_fog_density; +uniform float _cogl_fog_start; +uniform float _cogl_fog_end; /* Point options */ -uniform float point_size; +uniform float cogl_point_size_in; /*** _cogl_fixed_vertex_shader_main_start ***/ @@ -34,38 +34,40 @@ main (void) vec4 transformed_tex_coord; /* Calculate the transformed position */ - gl_Position = mvp_matrix * vertex_attrib; + gl_Position = cogl_modelview_projection_matrix * cogl_position_in; /* Copy across the point size from the uniform */ - gl_PointSize = point_size; + gl_PointSize = cogl_point_size_in; /* Calculate the transformed texture coordinate */ /*** _cogl_fixed_vertex_shader_frag_color_start ***/ /* Pass the interpolated vertex color on to the fragment shader */ - frag_color = color_attrib; + _cogl_color = cogl_color_in; /*** _cogl_fixed_vertex_shader_fog_start ***/ /* Estimate the distance from the eye using just the z-coordinate to use as the fog coord */ - vec4 eye_coord = modelview_matrix * vertex_attrib; + vec4 eye_coord = cogl_modelview_matrix * cogl_position_in; float fog_coord = abs (eye_coord.z / eye_coord.w); /* Calculate the fog amount per-vertex and interpolate it for the fragment shader */ /*** _cogl_fixed_vertex_shader_fog_exp ***/ - fog_amount = exp (-fog_density * fog_coord); + _cogl_fog_amount = exp (-fog_density * fog_coord); /*** _cogl_fixed_vertex_shader_fog_exp2 ***/ - fog_amount = exp (-fog_density * fog_coord - * fog_density * fog_coord); + _cogl_fog_amount = exp (-_cogl_fog_density * fog_coord + * _cogl_fog_density * fog_coord); /*** _cogl_fixed_vertex_shader_fog_linear ***/ - fog_amount = (fog_end - fog_coord) / (fog_end - fog_start); + _cogl_fog_amount = (_cogl_fog_end - fog_coord) / + (_cogl_fog_end - _cogl_fog_start); /*** _cogl_fixed_vertex_shader_fog_end ***/ - fog_amount = clamp (fog_amount, 0.0, 1.0); + _cogl_fog_amount = clamp (_cogl_fog_amount, 0.0, 1.0); /*** _cogl_fixed_vertex_shader_end ***/ } + diff --git a/cogl/driver/gles/cogl-gles2-wrapper.c b/cogl/driver/gles/cogl-gles2-wrapper.c index 032872099..e557fd28e 100644 --- a/cogl/driver/gles/cogl-gles2-wrapper.c +++ b/cogl/driver/gles/cogl-gles2-wrapper.c @@ -318,7 +318,7 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++) if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i)) g_string_append_printf (shader_source, - "attribute vec4 multi_tex_coord_attrib%d;\n", + "attribute vec4 cogl_tex_coord%d_in;\n", i); /* Find the biggest enabled texture unit index */ @@ -332,11 +332,11 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) if (n_texture_units > 0) { g_string_append_printf (shader_source, - "uniform mat4 texture_matrix[%d];\n", + "uniform mat4 cogl_texture_matrix[%d];\n", n_texture_units); g_string_append_printf (shader_source, - "varying vec2 tex_coord[%d];", + "varying vec2 _cogl_tex_coord[%d];", n_texture_units); } @@ -349,11 +349,11 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) { g_string_append_printf (shader_source, "transformed_tex_coord = " - "texture_matrix[%d] " - " * multi_tex_coord_attrib%d;\n", + "cogl_texture_matrix[%d] " + " * cogl_tex_coord%d_in;\n", i, i); g_string_append_printf (shader_source, - "tex_coord[%d] = transformed_tex_coord.st " + "_cogl_tex_coord[%d] = transformed_tex_coord.st " " / transformed_tex_coord.q;\n", i); } @@ -410,19 +410,21 @@ cogl_gles2_add_texture_lookup (int unit, _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); if (w->settings.tex_env[unit].texture_target == GL_TEXTURE_3D_OES) - g_string_append_printf (shader_source, "texture3D (texture_unit[%d], ", + g_string_append_printf (shader_source, + "texture3D (_cogl_texture_unit[%d], ", unit); else - g_string_append_printf (shader_source, "texture2D (texture_unit[%d], ", + g_string_append_printf (shader_source, + "texture2D (_cogl_texture_unit[%d], ", unit); /* If point sprite coord generation is being used then divert to the built-in varying var for that instead of the texture coordinates */ if (w->settings.tex_env[unit].point_sprite_coords) - g_string_append (shader_source, "gl_PointCoord"); + g_string_append (shader_source, "_cogl_point_coord"); else - g_string_append_printf (shader_source, "tex_coord[%d]", unit); + g_string_append_printf (shader_source, "_cogl_tex_coord[%d]", unit); g_string_append_printf (shader_source, ").%s", swizzle); } @@ -458,7 +460,7 @@ cogl_gles2_add_arg (int unit, break; case GL_CONSTANT: - g_string_append_printf (shader_source, "combine_constant[%d].%s", + g_string_append_printf (shader_source, "_cogl_combine_constant[%d].%s", unit, swizzle); break; @@ -470,7 +472,7 @@ cogl_gles2_add_arg (int unit, } /* flow through */ case GL_PRIMARY_COLOR: - g_string_append_printf (shader_source, "frag_color.%s", swizzle); + g_string_append_printf (shader_source, "_cogl_color.%s", swizzle); break; default: @@ -635,13 +637,13 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) if (n_texture_units > 0) { g_string_append_printf (shader_source, - "varying vec2 tex_coord[%d];\n", + "varying vec2 _cogl_tex_coord[%d];\n", n_texture_units); g_string_append (shader_source, _cogl_fixed_fragment_shader_texturing_options); g_string_append_printf (shader_source, - "uniform sampler2D texture_unit[%d];\n", + "uniform sampler2D _cogl_texture_unit[%d];\n", n_texture_units); } @@ -655,12 +657,12 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) apparent bug in the PowerVR drivers. Without it the alpha blending seems to stop working */ g_string_append (shader_source, - "vec4 frag_color_copy = frag_color;\n"); + "vec4 frag_color_copy = _cogl_color;\n"); /* If there are no textures units enabled then we can just directly use the color from the vertex shader */ if (n_texture_units == 0) - g_string_append (shader_source, "gl_FragColor = frag_color;\n"); + g_string_append (shader_source, "gl_FragColor = _cogl_color;\n"); else /* Otherwise we need to calculate the value based on the layer combine settings */ @@ -769,17 +771,17 @@ cogl_gles2_wrapper_get_locations (GLuint program, int i; uniforms->mvp_matrix_uniform - = glGetUniformLocation (program, "mvp_matrix"); + = glGetUniformLocation (program, "cogl_modelview_projection_matrix"); uniforms->modelview_matrix_uniform - = glGetUniformLocation (program, "modelview_matrix"); + = glGetUniformLocation (program, "cogl_modelview_matrix"); for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++) if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i)) { - char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i); - char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i); + char *matrix_var_name = g_strdup_printf ("cogl_texture_matrix[%d]", i); + char *sampler_var_name = g_strdup_printf ("_cogl_texture_unit[%d]", i); char *tex_coord_var_name = - g_strdup_printf ("multi_tex_coord_attrib%d", i); + g_strdup_printf ("cogl_tex_coord%d_in", i); uniforms->texture_matrix_uniforms[i] = glGetUniformLocation (program, matrix_var_name); @@ -800,30 +802,30 @@ cogl_gles2_wrapper_get_locations (GLuint program, } uniforms->fog_density_uniform - = glGetUniformLocation (program, "fog_density"); + = glGetUniformLocation (program, "_cogl_fog_density"); uniforms->fog_start_uniform - = glGetUniformLocation (program, "fog_start"); + = glGetUniformLocation (program, "_cogl_fog_start"); uniforms->fog_end_uniform - = glGetUniformLocation (program, "fog_end"); + = glGetUniformLocation (program, "_cogl_fog_end"); uniforms->fog_color_uniform - = glGetUniformLocation (program, "fog_color"); + = glGetUniformLocation (program, "_cogl_fog_color"); uniforms->alpha_test_ref_uniform - = glGetUniformLocation (program, "alpha_test_ref"); + = glGetUniformLocation (program, "_cogl_alpha_test_ref"); uniforms->point_size_uniform - = glGetUniformLocation (program, "point_size"); + = glGetUniformLocation (program, "cogl_point_size_in"); } static void cogl_gles2_wrapper_bind_attributes (GLuint program) { glBindAttribLocation (program, COGL_GLES2_WRAPPER_VERTEX_ATTRIB, - "vertex_attrib"); + "cogl_position_in"); glBindAttribLocation (program, COGL_GLES2_WRAPPER_COLOR_ATTRIB, - "color_attrib"); + "cogl_color_in"); glBindAttribLocation (program, COGL_GLES2_WRAPPER_NORMAL_ATTRIB, - "normal_attrib"); + "cogl_normal_in"); } static CoglGles2WrapperProgram *