X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fshader%2Fshader_api.c;h=5c18e55dacf9afd11edb0bcb0f73e9011d3b5453;hb=b9be69b85e8955fa9f773a65e7c3de5c4bb6e507;hp=26d0b3d476039c53b215bf738e42d958db63fa7c;hpb=088c42c5c3cb34bac98fce95e4f3d08642834112;p=mesa.git diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 26d0b3d4760..5c18e55dacf 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -35,10 +35,10 @@ */ -#include "glheader.h" -#include "context.h" -#include "hash.h" -#include "macros.h" +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/macros.h" #include "program.h" #include "prog_parameter.h" #include "prog_print.h" @@ -212,6 +212,35 @@ _mesa_lookup_shader_program(GLcontext *ctx, GLuint name) } +/** + * As above, but record an error if program is not found. + */ +static struct gl_shader_program * +_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name, + const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + else { + struct gl_shader_program *shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + if (shProg->Type != GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, caller); + return NULL; + } + return shProg; + } +} + + + + /** * Allocate a new gl_shader object, initialize it. */ @@ -233,15 +262,11 @@ _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) void _mesa_free_shader(GLcontext *ctx, struct gl_shader *sh) { - GLuint i; if (sh->Source) _mesa_free((void *) sh->Source); if (sh->InfoLog) _mesa_free(sh->InfoLog); - for (i = 0; i < sh->NumPrograms; i++) - _mesa_reference_program(ctx, &sh->Programs[i], NULL); - if (sh->Programs) - _mesa_free(sh->Programs); + _mesa_reference_program(ctx, &sh->Program, NULL); _mesa_free(sh); } @@ -314,6 +339,33 @@ _mesa_lookup_shader(GLcontext *ctx, GLuint name) } +/** + * As above, but record an error if shader is not found. + */ +static struct gl_shader * +_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + else { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + if (sh->Type == GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, caller); + return NULL; + } + return sh; + } +} + + + /** * Initialize context's shader state. */ @@ -360,26 +412,42 @@ copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src) } +static GLboolean +_mesa_is_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); + return shProg ? GL_TRUE : GL_FALSE; +} + + +static GLboolean +_mesa_is_shader(GLcontext *ctx, GLuint name) +{ + struct gl_shader *shader = _mesa_lookup_shader(ctx, name); + return shader ? GL_TRUE : GL_FALSE; +} + + /** * Called via ctx->Driver.AttachShader() */ static void _mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - GLuint n; - GLuint i; + struct gl_shader_program *shProg; + struct gl_shader *sh; + GLuint i, n; - if (!shProg || !sh) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glAttachShader(bad program or shader name)"); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader"); + if (!shProg) + return; + + sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader"); + if (!sh) { return; } n = shProg->NumShaders; - for (i = 0; i < n; i++) { if (shProg->Shaders[i] == sh) { /* already attached */ @@ -409,10 +477,9 @@ _mesa_get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name) { struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); + = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation"); return -1; } @@ -439,13 +506,14 @@ static void _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, const GLchar *name) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); + struct gl_shader_program *shProg; const GLint size = -1; /* unknown size */ GLint i, oldIndex; + GLenum datatype = GL_FLOAT_VEC4; + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glBindAttribLocation"); if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)"); return; } @@ -458,6 +526,11 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, return; } + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)"); + return; + } + if (shProg->LinkStatus) { /* get current index/location for the attribute */ oldIndex = _mesa_get_attrib_location(ctx, program, name); @@ -467,9 +540,10 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, } /* this will replace the current value if it's already in the list */ - i = _mesa_add_attribute(shProg->Attributes, name, size, index); + i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index); if (i < 0) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation"); + return; } if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) { @@ -539,11 +613,9 @@ _mesa_delete_program2(GLcontext *ctx, GLuint name) */ struct gl_shader_program *shProg; - shProg = _mesa_lookup_shader_program(ctx, name); - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)"); + shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram"); + if (!shProg) return; - } shProg->DeletePending = GL_TRUE; @@ -555,10 +627,11 @@ _mesa_delete_program2(GLcontext *ctx, GLuint name) static void _mesa_delete_shader(GLcontext *ctx, GLuint shader) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - if (!sh) { + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader"); + if (!sh) return; - } sh->DeletePending = GL_TRUE; @@ -570,16 +643,13 @@ _mesa_delete_shader(GLcontext *ctx, GLuint shader) static void _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); + struct gl_shader_program *shProg; GLuint n; GLuint i, j; - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glDetachShader(bad program or shader name)"); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); + if (!shProg) return; - } n = shProg->NumShaders; @@ -588,7 +658,7 @@ _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) /* found it */ struct gl_shader **newList; - /* derefernce */ + /* release */ _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); /* alloc new, smaller array */ @@ -624,8 +694,56 @@ _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) } /* not found */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glDetachShader(shader not found)"); + { + GLenum err; + if (_mesa_is_shader(ctx, shader)) + err = GL_INVALID_OPERATION; + else if (_mesa_is_program(ctx, shader)) + err = GL_INVALID_OPERATION; + else + err = GL_INVALID_VALUE; + _mesa_error(ctx, err, "glDetachProgram(shader)"); + return; + } +} + + +static GLint +sizeof_glsl_type(GLenum type) +{ + switch (type) { + case GL_FLOAT: + case GL_INT: + case GL_BOOL: + return 1; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + return 2; + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + return 4; + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + return 8; /* two float[4] vectors */ + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + return 12; /* three float[4] vectors */ + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + return 16; /* four float[4] vectors */ + default: + _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()"); + return 1; + } } @@ -634,17 +752,11 @@ _mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *nameOut) { - static const GLenum vec_types[] = { - GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 - }; - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - GLint sz; + struct gl_shader_program *shProg; - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib"); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); + if (!shProg) return; - } if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); @@ -653,11 +765,11 @@ _mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, copy_string(nameOut, maxLength, length, shProg->Attributes->Parameters[index].Name); - sz = shProg->Attributes->Parameters[index].Size; if (size) - *size = sz; + *size = shProg->Attributes->Parameters[index].Size + / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType); if (type) - *type = vec_types[sz]; /* XXX this is a temporary hack */ + *type = shProg->Attributes->Parameters[index].DataType; } @@ -669,15 +781,13 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *nameOut) { - const struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); + const struct gl_shader_program *shProg; const struct gl_program *prog; GLint progPos; - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform"); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); + if (!shProg) return; - } if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); @@ -702,8 +812,8 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index, copy_string(nameOut, maxLength, length, prog->Parameters->Parameters[progPos].Name); if (size) - *size = prog->Parameters->Parameters[progPos].Size; - + *size = prog->Parameters->Parameters[progPos].Size + / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType); if (type) *type = prog->Parameters->Parameters[progPos].DataType; } @@ -716,19 +826,16 @@ static void _mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders"); if (shProg) { GLuint i; - for (i = 0; i < maxCount && i < shProg->NumShaders; i++) { + for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { obj[i] = shProg->Shaders[i]->Name; } if (count) *count = i; } - else { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders"); - } } @@ -809,10 +916,9 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program, static void _mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) { - struct gl_shader *shader = _mesa_lookup_shader(ctx, name); + struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); if (!shader) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)"); return; } @@ -873,32 +979,30 @@ static void _mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *sourceOut) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + struct gl_shader *sh; + sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource"); if (!sh) { - GLenum err; - if (_mesa_lookup_shader_program(ctx, shader)) - err = GL_INVALID_OPERATION; - else - err = GL_INVALID_VALUE; - _mesa_error(ctx, err, "glGetShaderSource(shader)"); return; } copy_string(sourceOut, maxLength, length, sh->Source); } +#define MAX_UNIFORM_ELEMENTS 16 + /** - * Called via ctx->Driver.GetUniformfv(). + * Helper for GetUniformfv(), GetUniformiv() + * Returns number of elements written to 'params' output. */ -static void -_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, - GLfloat *params) +static GLuint +get_uniformfv(GLcontext *ctx, GLuint program, GLint location, + GLfloat *params) { struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); if (shProg) { if (shProg->Uniforms && - location >= 0 && location < shProg->Uniforms->NumUniforms) { + location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) { GLint progPos; GLuint i; const struct gl_program *prog = NULL; @@ -916,9 +1020,13 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, ASSERT(prog); if (prog) { + /* See uniformiv() below */ + assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS); + for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) { params[i] = prog->Parameters->ParameterValues[progPos][i]; } + return prog->Parameters->Parameters[progPos].Size; } } else { @@ -928,37 +1036,60 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, else { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)"); } + return 0; } /** - * Called via ctx->Driver.GetUniformLocation(). + * Called via ctx->Driver.GetUniformfv(). */ -static GLint -_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) +static void +_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, + GLfloat *params) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - if (!shProg) - return -1; - - return _mesa_lookup_uniform(shProg->Uniforms, name); + (void) get_uniformfv(ctx, program, location, params); } -static GLboolean -_mesa_is_program(GLcontext *ctx, GLuint name) +/** + * Called via ctx->Driver.GetUniformiv(). + */ +static void +_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location, + GLint *params) { - struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); - return shProg ? GL_TRUE : GL_FALSE; + GLfloat fparams[MAX_UNIFORM_ELEMENTS]; + GLuint n = get_uniformfv(ctx, program, location, fparams); + GLuint i; + assert(n <= MAX_UNIFORM_ELEMENTS); + for (i = 0; i < n; i++) { + params[i] = (GLint) fparams[i]; + } } -static GLboolean -_mesa_is_shader(GLcontext *ctx, GLuint name) +/** + * Called via ctx->Driver.GetUniformLocation(). + */ +static GLint +_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) { - struct gl_shader *shader = _mesa_lookup_shader(ctx, name); - return shader ? GL_TRUE : GL_FALSE; + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation"); + + if (!shProg) + return -1; + + if (shProg->LinkStatus == GL_FALSE) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)"); + return -1; + } + + /* XXX we should return -1 if the uniform was declared, but not + * actually used. + */ + + return _mesa_lookup_uniform(shProg->Uniforms, name); } @@ -969,16 +1100,11 @@ _mesa_is_shader(GLcontext *ctx, GLuint name) static void _mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - if (!sh) { - GLenum err; - if (_mesa_lookup_shader_program(ctx, shader)) - err = GL_INVALID_OPERATION; - else - err = GL_INVALID_VALUE; - _mesa_error(ctx, err, "glShaderSource(shaderObj)"); + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource"); + if (!sh) return; - } /* free old shader source string and install new one */ if (sh->Source) { @@ -995,12 +1121,11 @@ _mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) static void _mesa_compile_shader(GLcontext *ctx, GLuint shaderObj) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); + struct gl_shader *sh; - if (!sh) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)"); + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); + if (!sh) return; - } sh->CompileStatus = _slang_compile(ctx, sh); } @@ -1014,11 +1139,9 @@ _mesa_link_program(GLcontext *ctx, GLuint program) { struct gl_shader_program *shProg; - shProg = _mesa_lookup_shader_program(ctx, program); - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)"); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); + if (!shProg) return; - } FLUSH_VERTICES(ctx, _NEW_PROGRAM); @@ -1043,10 +1166,12 @@ _mesa_use_program(GLcontext *ctx, GLuint program) FLUSH_VERTICES(ctx, _NEW_PROGRAM); if (program) { - shProg = _mesa_lookup_shader_program(ctx, program); + shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glUseProgramObjectARB(programObj)"); + return; + } + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram"); return; } } @@ -1080,6 +1205,60 @@ update_textures_used(struct gl_program *prog) } +static GLboolean +is_sampler_type(GLenum type) +{ + switch (type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_SHADOW_ARB: + case GL_SAMPLER_1D_ARRAY_EXT: + case GL_SAMPLER_2D_ARRAY_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Check if the type given by userType is allowed to set a uniform of the + * target type. Generally, equivalence is required, but setting Boolean + * uniforms can be done with glUniformiv or glUniformfv. + */ +static GLboolean +compatible_types(GLenum userType, GLenum targetType) +{ + if (userType == targetType) + return GL_TRUE; + + if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 || + userType == GL_INT_VEC2)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 || + userType == GL_INT_VEC3)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 || + userType == GL_INT_VEC4)) + return GL_TRUE; + + if (is_sampler_type(targetType) && userType == GL_INT) + return GL_TRUE; + + return GL_FALSE; +} + + /** * Set the value of a program's uniform variable. * \param program the program whose uniform to update @@ -1093,6 +1272,12 @@ static void set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location, GLenum type, GLsizei count, GLint elems, const void *values) { + if (!compatible_types(type, + program->Parameters->Parameters[location].DataType)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); + return; + } + if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) { /* This controls which texture unit which is used by a sampler */ GLuint texUnit, sampler; @@ -1125,7 +1310,7 @@ set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location, /* ordinary uniform variable */ GLsizei k, i; - if (count * elems > program->Parameters->Parameters[location].Size) { + if (count * elems > (GLint) program->Parameters->Parameters[location].Size) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)"); return; } @@ -1170,7 +1355,6 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, if (location == -1) return; /* The standard specifies this as a no-op */ - if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)"); return; @@ -1226,39 +1410,100 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, } +static void +get_matrix_dims(GLenum type, GLint *rows, GLint *cols) +{ + switch (type) { + case GL_FLOAT_MAT2: + *rows = *cols = 2; + break; + case GL_FLOAT_MAT2x3: + *rows = 3; + *cols = 2; + break; + case GL_FLOAT_MAT2x4: + *rows = 4; + *cols = 2; + break; + case GL_FLOAT_MAT3: + *rows = 3; + *cols = 3; + break; + case GL_FLOAT_MAT3x2: + *rows = 2; + *cols = 3; + break; + case GL_FLOAT_MAT3x4: + *rows = 4; + *cols = 3; + break; + case GL_FLOAT_MAT4: + *rows = 4; + *cols = 4; + break; + case GL_FLOAT_MAT4x2: + *rows = 2; + *cols = 4; + break; + case GL_FLOAT_MAT4x3: + *rows = 3; + *cols = 4; + break; + default: + *rows = *cols = 0; + } +} + + static void set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program, - GLuint location, GLuint rows, GLuint cols, + GLuint location, GLuint count, + GLuint rows, GLuint cols, GLboolean transpose, const GLfloat *values) { + GLuint mat, row, col; + GLuint dst = location, src = 0; + GLint nr, nc; + + /* check that the number of rows, columns is correct */ + get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc); + if (rows != nr || cols != nc) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(matrix size mismatch"); + return; + } + /* * Note: the _columns_ of a matrix are stored in program registers, not - * the rows. + * the rows. So, the loops below look a little funny. + * XXX could optimize this a bit... */ - /* XXXX need to test 3x3 and 2x2 matrices... */ - if (transpose) { - GLuint row, col; - for (col = 0; col < cols; col++) { - GLfloat *v = program->Parameters->ParameterValues[location + col]; - for (row = 0; row < rows; row++) { - v[row] = values[row * cols + col]; - } - } - } - else { - GLuint row, col; + + /* loop over matrices */ + for (mat = 0; mat < count; mat++) { + + /* each matrix: */ for (col = 0; col < cols; col++) { - GLfloat *v = program->Parameters->ParameterValues[location + col]; + GLfloat *v = program->Parameters->ParameterValues[dst]; for (row = 0; row < rows; row++) { - v[row] = values[col * rows + row]; + if (transpose) { + v[row] = values[src + row * cols + col]; + } + else { + v[row] = values[src + col * rows + row]; + } } + dst++; } + + src += rows * cols; /* next matrix */ } } /** * Called by ctx->Driver.UniformMatrix(). + * Note: cols=2, rows=4 ==> array[2] of vec4 */ static void _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, @@ -1276,7 +1521,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, if (location == -1) return; /* The standard specifies this as a no-op */ - if (location < 0 || location >= shProg->Uniforms->NumUniforms) { + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)"); return; } @@ -1291,7 +1536,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, GLint loc = shProg->Uniforms->Uniforms[location].VertPos; if (loc >= 0) { set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base, - loc, rows, cols, transpose, values); + loc, count, rows, cols, transpose, values); } } @@ -1299,7 +1544,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, GLint loc = shProg->Uniforms->Uniforms[location].FragPos; if (loc >= 0) { set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base, - loc, rows, cols, transpose, values); + loc, count, rows, cols, transpose, values); } } } @@ -1309,15 +1554,19 @@ static void _mesa_validate_program(GLcontext *ctx, GLuint program) { struct gl_shader_program *shProg; - shProg = _mesa_lookup_shader_program(ctx, program); + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram"); if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)"); return; } - /* XXX temporary */ - shProg->Validated = GL_TRUE; - /* From the GL spec: + if (!shProg->LinkStatus) { + shProg->Validated = GL_FALSE; + return; + } + + /* From the GL spec, a program is invalid if any of these are true: + any two active samplers in the current program object are of different types, but refer to the same texture image unit, @@ -1330,6 +1579,8 @@ _mesa_validate_program(GLcontext *ctx, GLuint program) processing exceeds the combined limit on the total number of texture image units allowed. */ + + shProg->Validated = GL_TRUE; } @@ -1358,6 +1609,7 @@ _mesa_init_glsl_driver_functions(struct dd_function_table *driver) driver->GetShaderInfoLog = _mesa_get_shader_info_log; driver->GetShaderSource = _mesa_get_shader_source; driver->GetUniformfv = _mesa_get_uniformfv; + driver->GetUniformiv = _mesa_get_uniformiv; driver->GetUniformLocation = _mesa_get_uniform_location; driver->IsProgram = _mesa_is_program; driver->IsShader = _mesa_is_shader;