diff --git a/cogl/cogl-material-arbfp.c b/cogl/cogl-material-arbfp.c index 4d7930166..90ab3e4b0 100644 --- a/cogl/cogl-material-arbfp.c +++ b/cogl/cogl-material-arbfp.c @@ -79,6 +79,7 @@ typedef struct _CoglMaterialBackendARBfpPrivate CoglMaterial *authority_cache; unsigned long authority_cache_age; + CoglHandle user_program; GString *source; GLuint gl_program; gboolean *sampled; @@ -160,7 +161,7 @@ layers_arbfp_would_differ (CoglMaterialLayer **material0_layers, * generate. */ static CoglMaterial * -find_arbfp_authority (CoglMaterial *material) +find_arbfp_authority (CoglMaterial *material, CoglHandle user_program) { CoglMaterial *authority0; CoglMaterial *authority1; @@ -171,6 +172,9 @@ find_arbfp_authority (CoglMaterial *material) /* XXX: we'll need to update this when we add fog support to the * arbfp codegen */ + if (user_program != COGL_INVALID_HANDLE) + return material; + /* Find the first material that modifies state that affects the * arbfp codegen... */ authority0 = _cogl_material_get_authority (material, @@ -253,9 +257,13 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material, CoglMaterial *authority; CoglMaterialBackendARBfpPrivate *priv; CoglMaterialBackendARBfpPrivate *authority_priv; + CoglHandle user_program; _COGL_GET_CONTEXT (ctx, FALSE); + /* First validate that we can handle the current state using ARBfp + */ + if (!cogl_features_available (COGL_FEATURE_SHADERS_ARBFP)) return FALSE; @@ -263,11 +271,23 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material, if (ctx->legacy_fog_state.enabled) return FALSE; + user_program = cogl_material_get_user_program (material); + if (user_program != COGL_INVALID_HANDLE && + _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP) + return FALSE; + + /* Now lookup our ARBfp backend private state (allocating if + * necessary) that may contain a cache pointer refering us to the + * material's "arbfp-authority". + * + * The arbfp-authority is the oldest ancestor whos state will result in + * the same program being generated. + */ + /* Note: we allocate ARBfp private state for both the given material - * and the authority. (The oldest ancestor whos state will result in - * the same program being generated) The former will simply cache a - * pointer to the authority and the later will track the arbfp - * program that we will generate. + * and the arbfp-authority. The former will simply cache a pointer + * to the authority and the later will track the arbfp program that + * we will generate. */ if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)) @@ -285,16 +305,24 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material, * may invalidate authority_cache pointers. */ + /* If the given material has changed since we last cached its + * arbfp-authority then invalidate our cache and then search the + * material's ancestors for one with matching fragment processing + * state. */ + if (priv->authority_cache && priv->authority_cache_age != _cogl_material_get_age (material)) invalidate_arbfp_authority_cache (material); if (!priv->authority_cache) { - priv->authority_cache = find_arbfp_authority (material); + priv->authority_cache = find_arbfp_authority (material, user_program); priv->authority_cache_age = _cogl_material_get_age (material); } + /* Now we have our arbfp-authority fetch the ARBfp backend private + * state from it (allocting if necessary) */ + authority = priv->authority_cache; if (!(authority->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)) { @@ -304,7 +332,9 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material, } authority_priv = authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; - if (authority_priv->gl_program == 0) + authority_priv->user_program = user_program; + + if (user_program == COGL_INVALID_HANDLE && authority_priv->gl_program == 0) { /* We reuse a single grow-only GString for ARBfp code-gen */ g_string_set_size (ctx->arbfp_source_buffer, 0); @@ -912,6 +942,7 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material, CoglMaterial *arbfp_authority = get_arbfp_authority (material); CoglMaterialBackendARBfpPrivate *priv = arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; + GLuint gl_program; _COGL_GET_CONTEXT (ctx, FALSE); @@ -954,9 +985,16 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material, g_free (priv->sampled); priv->sampled = NULL; } - else - GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program)); + if (priv->user_program != COGL_INVALID_HANDLE) + { + CoglProgram *program = (CoglProgram *)priv->user_program; + gl_program = program->gl_handle; + } + else + gl_program = priv->gl_program; + + GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program)); _cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP); return TRUE; @@ -968,17 +1006,23 @@ _cogl_material_backend_arbfp_material_pre_change_notify ( CoglMaterialState change, const CoglColor *new_color) { - CoglMaterialBackendARBfpPrivate *priv = - material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; + CoglMaterialBackendARBfpPrivate *priv; static const unsigned long fragment_op_changes = - COGL_MATERIAL_STATE_LAYERS; + COGL_MATERIAL_STATE_LAYERS | + COGL_MATERIAL_STATE_USER_SHADER; /* TODO: COGL_MATERIAL_STATE_FOG */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK && - priv->gl_program && - change & fragment_op_changes) + if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK) || + !(change & fragment_op_changes)) + return; + + priv = material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; + + priv->user_program = COGL_INVALID_HANDLE; + + if (priv->gl_program) { GE (glDeletePrograms (1, &priv->gl_program)); priv->gl_program = 0; diff --git a/cogl/cogl-material-glsl.c b/cogl/cogl-material-glsl.c index 0b2cf6eb8..ac0124e5d 100644 --- a/cogl/cogl-material-glsl.c +++ b/cogl/cogl-material-glsl.c @@ -63,28 +63,20 @@ _cogl_material_backend_glsl_start (CoglMaterial *material, int n_layers, unsigned long materials_difference) { + CoglHandle program; + _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) return FALSE; - if (materials_difference & COGL_MATERIAL_STATE_USER_SHADER) - { - CoglMaterial *authority = - _cogl_material_get_authority (material, - COGL_MATERIAL_STATE_USER_SHADER); - CoglHandle program = authority->big_state->user_program; + program = cogl_material_get_user_program (material); + if (program == COGL_INVALID_HANDLE || + _cogl_program_get_language (program) != COGL_SHADER_LANGUAGE_GLSL) + return FALSE; /* XXX: change me when we support code generation here */ - if (program == COGL_INVALID_HANDLE) - return FALSE; /* XXX: change me when we support code generation here */ - - _cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL); - return TRUE; - } - - /* TODO: also support code generation */ - - return FALSE; + _cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL); + return TRUE; } gboolean diff --git a/cogl/cogl-shader-private.h b/cogl/cogl-shader-private.h index 878ab5552..cf02bc92b 100644 --- a/cogl/cogl-shader-private.h +++ b/cogl/cogl-shader-private.h @@ -28,13 +28,26 @@ typedef struct _CoglShader CoglShader; +typedef enum +{ + COGL_SHADER_LANGUAGE_GLSL, +#ifdef HAVE_COGL_GL + COGL_SHADER_LANGUAGE_ARBFP +#endif +} CoglShaderLanguage; + struct _CoglShader { CoglHandleObject _parent; GLuint gl_handle; + char *arbfp_source; CoglShaderType type; + CoglShaderLanguage language; }; CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle); +CoglShaderLanguage +_cogl_program_get_language (CoglHandle handle); + #endif /* __COGL_SHADER_H */ diff --git a/cogl/cogl-shader.c b/cogl/cogl-shader.c index a34e47670..50f444c6f 100644 --- a/cogl/cogl-shader.c +++ b/cogl/cogl-shader.c @@ -33,6 +33,8 @@ #include +#include + #ifdef HAVE_COGL_GL #define glCreateShader ctx->drv.pf_glCreateShader #define glGetShaderiv ctx->drv.pf_glGetShaderiv @@ -58,7 +60,14 @@ _cogl_shader_free (CoglShader *shader) /* Frees shader resources but its handle is not released! Do that separately before this! */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - glDeleteShader (shader->gl_handle); + +#ifdef HAVE_COGL_GL + if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) + g_free (shader->arbfp_source); + else +#endif + if (shader->gl_handle) + GE (glDeleteShader (shader->gl_handle)); g_slice_free (CoglShader, shader); } @@ -67,23 +76,23 @@ CoglHandle cogl_create_shader (CoglShaderType type) { CoglShader *shader; - GLenum gl_type; GET_CONTEXT (ctx, COGL_INVALID_HANDLE); - if (type == COGL_SHADER_TYPE_VERTEX) - gl_type = GL_VERTEX_SHADER; - else if (type == COGL_SHADER_TYPE_FRAGMENT) - gl_type = GL_FRAGMENT_SHADER; - else + switch (type) { + case COGL_SHADER_TYPE_VERTEX: + case COGL_SHADER_TYPE_FRAGMENT: + break; + default: g_warning ("Unexpected shader type (0x%08lX) given to " "cogl_create_shader", (unsigned long) type); return COGL_INVALID_HANDLE; } shader = g_slice_new (CoglShader); - shader->gl_handle = glCreateShader (gl_type); + shader->language = COGL_SHADER_LANGUAGE_GLSL; + shader->gl_handle = 0; shader->type = type; return _cogl_shader_handle_new (shader); @@ -94,6 +103,8 @@ cogl_shader_source (CoglHandle handle, const char *source) { CoglShader *shader; + CoglShaderLanguage language; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_shader (handle)) @@ -101,7 +112,57 @@ cogl_shader_source (CoglHandle handle, shader = _cogl_shader_pointer_from_handle (handle); - glShaderSource (shader->gl_handle, 1, &source, NULL); +#ifdef HAVE_COGL_GL + if (strncmp (source, "!!ARBfp1.0", 10) == 0) + language = COGL_SHADER_LANGUAGE_ARBFP; + else +#endif + 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) + { + g_free (shader->arbfp_source); + shader->arbfp_source = NULL; + } +#endif + else + { + if (shader->gl_handle) + GE (glDeleteShader (shader->gl_handle)); + } + } + +#ifdef HAVE_COGL_GL + if (language == COGL_SHADER_LANGUAGE_ARBFP) + shader->arbfp_source = g_strdup (source); + else +#endif + { + if (!shader->gl_handle) + { + 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; + } + + shader->gl_handle = glCreateShader (gl_type); + } + glShaderSource (shader->gl_handle, 1, &source, NULL); + } + + shader->language = language; } void @@ -115,15 +176,14 @@ cogl_shader_compile (CoglHandle handle) shader = _cogl_shader_pointer_from_handle (handle); - glCompileShader (shader->gl_handle); + if (shader->language == COGL_SHADER_LANGUAGE_GLSL) + GE (glCompileShader (shader->gl_handle)); } char * cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; - char buffer[512]; - int len = 0; GET_CONTEXT (ctx, NULL); @@ -132,10 +192,21 @@ cogl_shader_get_info_log (CoglHandle handle) shader = _cogl_shader_pointer_from_handle (handle); - glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); - buffer[len] = '\0'; - - return g_strdup (buffer); + if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) + { + /* ARBfp exposes a program error string, but since cogl_program + * doesn't have any API to query an error log it is not currently + * exposed. */ + return ""; + } + else + { + char buffer[512]; + int len = 0; + glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); + buffer[len] = '\0'; + return g_strdup (buffer); + } } CoglShaderType @@ -168,11 +239,18 @@ cogl_shader_is_compiled (CoglHandle handle) shader = _cogl_shader_pointer_from_handle (handle); - GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); - if (status == GL_TRUE) +#ifdef HAVE_COGL_GL + if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) return TRUE; else - return FALSE; +#endif + { + GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); + if (status == GL_TRUE) + return TRUE; + else + return FALSE; + } } #else /* HAVE_COGL_GLES */ diff --git a/cogl/cogl.c b/cogl/cogl.c index 624a63c78..229acde52 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -496,6 +496,9 @@ cogl_get_features (void) if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_PBOS)) ctx->feature_flags &= ~COGL_FEATURE_PBOS; + if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ARBFP)) + ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP; + if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_GLSL)) ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL; @@ -521,9 +524,6 @@ _cogl_features_available_private (CoglFeatureFlagsPrivate features) if (!ctx->features_cached) _cogl_features_init (); - if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ARBFP)) - ctx->feature_flags_private &= ~COGL_FEATURE_SHADERS_ARBFP; - return (ctx->feature_flags_private & features) == features; } diff --git a/cogl/driver/gl/cogl-program.c b/cogl/driver/gl/cogl-program.c index fd0a546af..7b808b9c8 100644 --- a/cogl/driver/gl/cogl-program.c +++ b/cogl/driver/gl/cogl-program.c @@ -16,9 +16,12 @@ * 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 . + * License along with this library. If not, see + * . * * + * Authors: + * Robert Bragg */ #ifdef HAVE_CONFIG_H @@ -36,6 +39,8 @@ #include +#include + #define glCreateProgram ctx->drv.pf_glCreateProgram #define glAttachShader ctx->drv.pf_glAttachShader #define glUseProgram ctx->drv.pf_glUseProgram @@ -62,6 +67,13 @@ #define glUniformMatrix4fv ctx->drv.pf_glUniformMatrix4fv #define glDeleteProgram ctx->drv.pf_glDeleteProgram +#define glProgramString ctx->drv.pf_glProgramString +#define glBindProgram ctx->drv.pf_glBindProgram +#define glDeletePrograms ctx->drv.pf_glDeletePrograms +#define glGenPrograms ctx->drv.pf_glGenPrograms +#define glProgramLocalParameter4fv ctx->drv.pf_glProgramLocalParameter4fv + + static void _cogl_program_free (CoglProgram *program); COGL_HANDLE_DEFINE (Program, program); @@ -73,7 +85,14 @@ _cogl_program_free (CoglProgram *program) /* Frees program resources but its handle is not released! Do that separately before this! */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - GE (glDeleteProgram (program->gl_handle)); + + if (program->gl_handle) + { + if (program->language == COGL_SHADER_LANGUAGE_ARBFP) + GE (glDeletePrograms (1, &program->gl_handle)); + else + GE (glDeleteProgram (program->gl_handle)); + } g_slice_free (CoglProgram, program); } @@ -84,8 +103,7 @@ cogl_create_program (void) CoglProgram *program; _COGL_GET_CONTEXT (ctx, NULL); - program = g_slice_new (CoglProgram); - program->gl_handle = glCreateProgram (); + program = g_slice_new0 (CoglProgram); return _cogl_program_handle_new (program); } @@ -96,16 +114,63 @@ cogl_program_attach_shader (CoglHandle program_handle, { CoglProgram *program; CoglShader *shader; + CoglShaderLanguage language; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle)) - return; + g_return_if_fail (cogl_is_program (program_handle)); + g_return_if_fail (cogl_is_shader (shader_handle)); program = _cogl_program_pointer_from_handle (program_handle); shader = _cogl_shader_pointer_from_handle (shader_handle); - GE (glAttachShader (program->gl_handle, shader->gl_handle)); + language = shader->language; + + /* We only allow attaching one ARBfp shader to a program */ + if (language == COGL_SHADER_LANGUAGE_ARBFP) + g_return_if_fail (program->gl_handle == 0); + + program->language = language; + + if (language == COGL_SHADER_LANGUAGE_ARBFP) + { +#ifdef COGL_GL_DEBUG + GLenum gl_error; +#endif + + GE (glGenPrograms (1, &program->gl_handle)); + + GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, program->gl_handle)); + +#ifdef COGL_GL_DEBUG + while ((gl_error = glGetError ()) != GL_NO_ERROR) + ; +#endif + glProgramString (GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + strlen (shader->arbfp_source), + shader->arbfp_source); +#ifdef COGL_GL_DEBUG + gl_error = glGetError (); + if (gl_error != GL_NO_ERROR) + { + g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s", + G_STRLOC, + gl_error, + shader->arbfp_source, + glGetString (GL_PROGRAM_ERROR_STRING_ARB)); + } +#endif + } + else + { + if (!program->gl_handle) + program->gl_handle = glCreateProgram (); + GE (glAttachShader (program->gl_handle, shader->gl_handle)); + } + + /* NB: There is no separation between shader objects and program + * objects for ARBfp */ } void @@ -119,7 +184,11 @@ cogl_program_link (CoglHandle handle) program = _cogl_program_pointer_from_handle (handle); - GE (glLinkProgram (program->gl_handle)); + if (program->language == COGL_SHADER_LANGUAGE_GLSL && + program->gl_handle) + GE (glLinkProgram (program->gl_handle)); + + program->is_linked = TRUE; } void @@ -130,6 +199,12 @@ cogl_program_use (CoglHandle handle) g_return_if_fail (handle == COGL_INVALID_HANDLE || cogl_is_program (handle)); + if (handle != COGL_INVALID_HANDLE) + { + CoglProgram *program = handle; + g_return_if_fail (program->is_linked); + } + if (ctx->current_program == 0 && handle != 0) ctx->legacy_state_set++; else if (handle == 0 && ctx->current_program != 0) @@ -142,6 +217,39 @@ cogl_program_use (CoglHandle handle) ctx->current_program = handle; } +/* ARBfp local parameters can be referenced like: + * + * "program.local[5]" + * ^14char offset (after whitespace is stripped) + */ +static int +get_local_param_index (const char *uniform_name) +{ + char *input = g_strdup (uniform_name); + int i; + char *p = input; + char *endptr; + int _index; + + for (i = 0; input[i] != '\0'; i++) + if (input[i] != '_' && input[i] != '\t') + *p++ = input[i]; + input[i] = '\0'; + + g_return_val_if_fail (strncmp ("program.local[", input, 14) == 0, -1); + + _index = g_ascii_strtoull (input + 14, &endptr, 10); + g_return_val_if_fail (endptr != input + 14, -1); + g_return_val_if_fail (*endptr == ']', -1); + + g_return_val_if_fail (_index >= 0 && + _index < COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS, -1); + + g_free (input); + + return _index; +} + int cogl_program_get_uniform_location (CoglHandle handle, const char *uniform_name) @@ -154,7 +262,10 @@ cogl_program_get_uniform_location (CoglHandle handle, program = _cogl_program_pointer_from_handle (handle); - return glGetUniformLocation (program->gl_handle, uniform_name); + if (program->language == COGL_SHADER_LANGUAGE_ARBFP) + return get_local_param_index (uniform_name); + else + return glGetUniformLocation (program->gl_handle, uniform_name); } void @@ -169,6 +280,8 @@ cogl_program_uniform_1f (int uniform_no, g_return_if_fail (program != NULL); + g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP); + _cogl_gl_use_program_wrapper (program); GE (glUniform1f (uniform_no, value)); @@ -186,15 +299,17 @@ cogl_program_uniform_1i (int uniform_no, g_return_if_fail (program != NULL); + g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP); + _cogl_gl_use_program_wrapper (program); GE (glUniform1i (uniform_no, value)); } void -cogl_program_uniform_float (int uniform_no, - int size, - int count, +cogl_program_uniform_float (int uniform_no, + int size, + int count, const GLfloat *value) { CoglProgram *program; @@ -205,24 +320,47 @@ cogl_program_uniform_float (int uniform_no, g_return_if_fail (program != NULL); - _cogl_gl_use_program_wrapper (program); - - switch (size) + if (program->language == COGL_SHADER_LANGUAGE_ARBFP) { - case 1: - GE (glUniform1fv (uniform_no, count, value)); - break; - case 2: - GE (glUniform2fv (uniform_no, count, value)); - break; - case 3: - GE (glUniform3fv (uniform_no, count, value)); - break; - case 4: - GE (glUniform4fv (uniform_no, count, value)); - break; - default: - g_warning ("%s called with invalid size parameter", G_STRFUNC); + unsigned int _index = uniform_no; + unsigned int index_end = _index + count; + int i; + int j; + + g_return_if_fail (size == 4); + + GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, program->gl_handle)); + + for (i = _index; i < index_end; i++) + for (j = 0; j < 4; j++) + program->arbfp_local_params[i][j] = *(value++); + + for (i = _index; i < index_end; i++) + GE (glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, + i, + &program->arbfp_local_params[i][0])); + } + else + { + _cogl_gl_use_program_wrapper (program); + + switch (size) + { + case 1: + GE (glUniform1fv (uniform_no, count, value)); + break; + case 2: + GE (glUniform2fv (uniform_no, count, value)); + break; + case 3: + GE (glUniform3fv (uniform_no, count, value)); + break; + case 4: + GE (glUniform4fv (uniform_no, count, value)); + break; + default: + g_warning ("%s called with invalid size parameter", G_STRFUNC); + } } } @@ -276,6 +414,8 @@ cogl_program_uniform_matrix (int uniform_no, g_return_if_fail (program != NULL); + g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP); + _cogl_gl_use_program_wrapper (program); switch (size) @@ -293,3 +433,11 @@ cogl_program_uniform_matrix (int uniform_no, g_warning ("%s called with invalid size parameter", G_STRFUNC); } } + +CoglShaderLanguage +_cogl_program_get_language (CoglHandle handle) +{ + CoglProgram *program = handle; + return program->language; +} + diff --git a/cogl/driver/gl/cogl-program.h b/cogl/driver/gl/cogl-program.h index 5d5d7ec38..4287ce1e9 100644 --- a/cogl/driver/gl/cogl-program.h +++ b/cogl/driver/gl/cogl-program.h @@ -25,13 +25,20 @@ #define __COGL_PROGRAM_H #include "cogl-handle.h" +#include "cogl-shader-private.h" typedef struct _CoglProgram CoglProgram; +/* The ARBfp spec says at least 24 indices are available */ +#define COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS 24 + struct _CoglProgram { - CoglHandleObject _parent; - GLuint gl_handle; + CoglHandleObject _parent; + CoglShaderLanguage language; + float arbfp_local_params[COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS][4]; + GLuint gl_handle; + gboolean is_linked; }; CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle); diff --git a/cogl/driver/gles/cogl-program.c b/cogl/driver/gles/cogl-program.c index 7852cf99a..a99fbcd56 100644 --- a/cogl/driver/gles/cogl-program.c +++ b/cogl/driver/gles/cogl-program.c @@ -365,3 +365,10 @@ cogl_program_uniform_matrix (int uniform_no, #endif /* HAVE_COGL_GLES2 */ + +CoglShaderLanguage +_cogl_program_get_language (CoglHandle handle) +{ + return COGL_SHADER_LANGUAGE_GLSL; +} +