X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fshader%2Fshader_api.c;h=5c18e55dacf9afd11edb0bcb0f73e9011d3b5453;hb=b9be69b85e8955fa9f773a65e7c3de5c4bb6e507;hp=1a931326afa3a9d5117429fb32c85ebce5368bdd;hpb=6101fe641cd506422d0b2735dfcaa61174684ec4;p=mesa.git diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 1a931326afa..5c18e55dacf 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -35,14 +35,15 @@ */ -#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" #include "prog_statevars.h" +#include "prog_uniform.h" #include "shader/shader_api.h" #include "shader/slang/slang_compile.h" #include "shader/slang/slang_link.h" @@ -52,7 +53,7 @@ /** * Allocate a new gl_shader_program object, initialize it. */ -struct gl_shader_program * +static struct gl_shader_program * _mesa_new_shader_program(GLcontext *ctx, GLuint name) { struct gl_shader_program *shProg; @@ -74,26 +75,11 @@ void _mesa_clear_shader_program_data(GLcontext *ctx, struct gl_shader_program *shProg) { - if (shProg->VertexProgram) { - if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) { - /* to prevent a double-free in the next call */ - shProg->VertexProgram->Base.Parameters = NULL; - } - _mesa_delete_program(ctx, &shProg->VertexProgram->Base); - shProg->VertexProgram = NULL; - } - - if (shProg->FragmentProgram) { - if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) { - /* to prevent a double-free in the next call */ - shProg->FragmentProgram->Base.Parameters = NULL; - } - _mesa_delete_program(ctx, &shProg->FragmentProgram->Base); - shProg->FragmentProgram = NULL; - } + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); if (shProg->Uniforms) { - _mesa_free_parameter_list(shProg->Uniforms); + _mesa_free_uniform_list(shProg->Uniforms); shProg->Uniforms = NULL; } @@ -127,10 +113,17 @@ _mesa_free_shader_program_data(GLcontext *ctx, for (i = 0; i < shProg->NumShaders; i++) { _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); } + shProg->NumShaders = 0; + if (shProg->Shaders) { _mesa_free(shProg->Shaders); shProg->Shaders = NULL; } + + if (shProg->InfoLog) { + _mesa_free(shProg->InfoLog); + shProg->InfoLog = NULL; + } } @@ -141,10 +134,7 @@ void _mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) { _mesa_free_shader_program_data(ctx, shProg); - if (shProg->Shaders) { - _mesa_free(shProg->Shaders); - shProg->Shaders = NULL; - } + _mesa_free(shProg); } @@ -173,8 +163,10 @@ _mesa_reference_shader_program(GLcontext *ctx, ASSERT(old->RefCount > 0); old->RefCount--; - /*printf("SHPROG DECR %p (%d) to %d\n", - (void*) old, old->Name, old->RefCount);*/ +#if 0 + printf("ShaderProgram %p ID=%u RefCount-- to %d\n", + (void *) old, old->Name, old->RefCount); +#endif deleteFlag = (old->RefCount == 0); if (deleteFlag) { @@ -188,8 +180,10 @@ _mesa_reference_shader_program(GLcontext *ctx, if (shProg) { shProg->RefCount++; - /*printf("SHPROG INCR %p (%d) to %d\n", - (void*) shProg, shProg->Name, shProg->RefCount);*/ +#if 0 + printf("ShaderProgram %p ID=%u RefCount++ to %d\n", + (void *) shProg, shProg->Name, shProg->RefCount); +#endif *ptr = shProg; } } @@ -218,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. */ @@ -239,17 +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++) { - assert(sh->Programs[i]); - _mesa_delete_program(ctx, sh->Programs[i]); - } - if (sh->Programs) - _mesa_free(sh->Programs); + _mesa_reference_program(ctx, &sh->Program, NULL); _mesa_free(sh); } @@ -322,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. */ @@ -332,7 +376,7 @@ _mesa_init_shader_state(GLcontext * ctx) * are generated by the GLSL compiler. */ ctx->Shader.EmitHighLevelInstructions = GL_TRUE; - ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */ + ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */ ctx->Shader.EmitComments = GL_FALSE; } @@ -368,24 +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() */ -void +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); - const GLuint n = shProg->NumShaders; - 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 */ @@ -410,17 +472,48 @@ _mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader) } -void +static GLint +_mesa_get_attrib_location(GLcontext *ctx, GLuint program, + const GLchar *name) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); + + if (!shProg) { + return -1; + } + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetAttribLocation(program not linked)"); + return -1; + } + + if (!name) + return -1; + + if (shProg->Attributes) { + GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name); + if (i >= 0) { + return shProg->Attributes->Parameters[i].StateIndexes[0]; + } + } + return -1; +} + + +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; } @@ -433,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); @@ -442,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) { @@ -456,7 +555,7 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, } -GLuint +static GLuint _mesa_create_shader(GLcontext *ctx, GLenum type) { struct gl_shader *sh; @@ -480,7 +579,7 @@ _mesa_create_shader(GLcontext *ctx, GLenum type) } -GLuint +static GLuint _mesa_create_program(GLcontext *ctx) { GLuint name; @@ -501,7 +600,7 @@ _mesa_create_program(GLcontext *ctx) * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's * DeleteProgramARB. */ -void +static void _mesa_delete_program2(GLcontext *ctx, GLuint name) { /* @@ -514,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; @@ -527,13 +624,14 @@ _mesa_delete_program2(GLcontext *ctx, GLuint name) } -void +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; @@ -542,26 +640,25 @@ _mesa_delete_shader(GLcontext *ctx, GLuint shader) } -void +static void _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - const GLuint n = shProg->NumShaders; + 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; for (i = 0; i < n; i++) { if (shProg->Shaders[i]->Name == shader) { /* found it */ struct gl_shader **newList; - /* derefernce */ + /* release */ _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); /* alloc new, smaller array */ @@ -597,27 +694,69 @@ _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; + } } -void +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; + } +} + + +static void _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)"); @@ -626,113 +765,81 @@ _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; } /** * Called via ctx->Driver.GetActiveUniform(). */ -void +static void _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *nameOut) { - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - GLuint ind, j; + 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->NumParameters) { + if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); return; } - ind = 0; - for (j = 0; j < shProg->Uniforms->NumParameters; j++) { - if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM || - shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) { - if (ind == index) { - /* found it */ - copy_string(nameOut, maxLength, length, - shProg->Uniforms->Parameters[j].Name); - if (size) - *size = shProg->Uniforms->Parameters[j].Size; - if (type) - *type = shProg->Uniforms->Parameters[j].DataType; - return; - } - ind++; + progPos = shProg->Uniforms->Uniforms[index].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[index].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; } } - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); + if (!prog || progPos < 0) + return; /* should never happen */ + + if (nameOut) + copy_string(nameOut, maxLength, length, + prog->Parameters->Parameters[progPos].Name); + if (size) + *size = prog->Parameters->Parameters[progPos].Size + / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType); + if (type) + *type = prog->Parameters->Parameters[progPos].DataType; } /** * Called via ctx->Driver.GetAttachedShaders(). */ -void +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) { - GLint i; - for (i = 0; i < maxCount && i < shProg->NumShaders; i++) { + GLuint 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"); - } } -GLint -_mesa_get_attrib_location(GLcontext *ctx, GLuint program, - const GLchar *name) -{ - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation"); - return -1; - } - - if (!shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetAttribLocation(program not linked)"); - return -1; - } - - if (!name) - return -1; - - if (shProg->Attributes) { - GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name); - if (i >= 0) { - return shProg->Attributes->Parameters[i].StateIndexes[0]; - } - } - return -1; -} - - -GLuint +static GLuint _mesa_get_handle(GLcontext *ctx, GLenum pname) { #if 0 @@ -756,7 +863,7 @@ _mesa_get_handle(GLcontext *ctx, GLenum pname) } -void +static void _mesa_get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params) { @@ -792,14 +899,10 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program, PROGRAM_INPUT) + 1; break; case GL_ACTIVE_UNIFORMS: - *params - = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM) - + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER); + *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; break; case GL_ACTIVE_UNIFORM_MAX_LENGTH: - *params = MAX2( - _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM), - _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER)); + *params = _mesa_longest_uniform_name(shProg->Uniforms); if (*params > 0) (*params)++; /* add one for terminating zero */ break; @@ -810,13 +913,12 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program, } -void +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; } @@ -843,7 +945,7 @@ _mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) } -void +static void _mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { @@ -857,7 +959,7 @@ _mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, } -void +static void _mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { @@ -873,86 +975,121 @@ _mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, /** * Called via ctx->Driver.GetShaderSource(). */ -void +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) { - _mesa_error(ctx, GL_INVALID_VALUE, "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. */ -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) { - GLint i; - if (location >= 0 && location < shProg->Uniforms->NumParameters) { - for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) { - params[i] = shProg->Uniforms->ParameterValues[location][i]; + if (shProg->Uniforms && + location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) { + GLint progPos; + GLuint i; + const struct gl_program *prog = NULL; + + progPos = shProg->Uniforms->Uniforms[location].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[location].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; + } + } + + 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 { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)"); } } else { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)"); } + return 0; } /** - * Called via ctx->Driver.GetUniformLocation(). + * Called via ctx->Driver.GetUniformfv(). */ -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) { - GLuint loc; - for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) { - const struct gl_program_parameter *u - = shProg->Uniforms->Parameters + loc; - /* XXX this is a temporary simplification / short-cut. - * We need to handle things like "e.c[0].b" as seen in the - * GLSL orange book, page 189. - */ - if ((u->Type == PROGRAM_UNIFORM || - u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) { - return loc; - } - } - } - return -1; - + (void) get_uniformfv(ctx, program, location, params); } -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]; + } } -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); } @@ -960,14 +1097,14 @@ _mesa_is_shader(GLcontext *ctx, GLuint name) /** * Called via ctx->Driver.ShaderSource() */ -void +static void _mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - if (!sh) { - _mesa_error(ctx, GL_INVALID_VALUE, "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) { @@ -981,15 +1118,14 @@ _mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) /** * Called via ctx->Driver.CompileShader() */ -void +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); } @@ -998,16 +1134,16 @@ _mesa_compile_shader(GLcontext *ctx, GLuint shaderObj) /** * Called via ctx->Driver.LinkProgram() */ -void +static void _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); _slang_link(ctx, program, shProg); } @@ -1030,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; } } @@ -1045,46 +1183,181 @@ _mesa_use_program(GLcontext *ctx, GLuint program) } + /** - * Called via ctx->Driver.Uniform(). + * Update the vertex and fragment program's TexturesUsed arrays. */ -void -_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, - const GLvoid *values, GLenum type) +static void +update_textures_used(struct gl_program *prog) { - struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; - GLint elems, i, k; + GLuint s; - if (!shProg || !shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); - return; + memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed)); + + for (s = 0; s < MAX_SAMPLERS; s++) { + if (prog->SamplersUsed & (1 << s)) { + GLuint u = prog->SamplerUnits[s]; + GLuint t = prog->SamplerTargets[s]; + assert(u < MAX_TEXTURE_IMAGE_UNITS); + prog->TexturesUsed[u] |= (1 << t); + } } +} - if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) { - _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)"); + +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 + * \param location the location/index of the uniform + * \param type the datatype of the uniform + * \param count the number of uniforms to set + * \param elems number of elements per uniform + * \param values the new values + */ +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; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM); + if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) { + /* This controls which texture unit which is used by a sampler */ + GLuint texUnit, sampler; - /* - * If we're setting a sampler, we must use glUniformi1()! - */ - if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) { - GLint unit; + /* data type for setting samplers must be int */ if (type != GL_INT || count != 1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(only glUniform1i can be used " "to set sampler uniforms)"); return; } + + sampler = (GLuint) program->Parameters->ParameterValues[location][0]; + texUnit = ((GLuint *) values)[0]; + /* check that the sampler (tex unit index) is legal */ - unit = ((GLint *) values)[0]; - if (unit >= ctx->Const.MaxTextureImageUnits) { + if (texUnit >= ctx->Const.MaxTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1(invalid sampler/tex unit index)"); return; } + + /* This maps a sampler to a texture unit: */ + program->SamplerUnits[sampler] = texUnit; + update_textures_used(program); + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + } + else { + /* ordinary uniform variable */ + GLsizei k, i; + + if (count * elems > (GLint) program->Parameters->Parameters[location].Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)"); + return; + } + + for (k = 0; k < count; k++) { + GLfloat *uniformVal = program->Parameters->ParameterValues[location + k]; + if (type == GL_INT || + type == GL_INT_VEC2 || + type == GL_INT_VEC3 || + type == GL_INT_VEC4) { + const GLint *iValues = ((const GLint *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = (GLfloat) iValues[i]; + } + } + else { + const GLfloat *fValues = ((const GLfloat *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = fValues[i]; + } + } + } + } +} + + +/** + * Called via ctx->Driver.Uniform(). + */ +static void +_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, + const GLvoid *values, GLenum type) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + GLint elems; + + if (!shProg || !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); + return; + } + + 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; } if (count < 0) { @@ -1114,55 +1387,141 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, return; } - if (count * elems > shProg->Uniforms->Parameters[location].Size) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)"); - return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + /* A uniform var may be used by both a vertex shader and a fragment + * shader. We may need to update one or both shader's uniform here: + */ + if (shProg->VertexProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].VertPos; + if (loc >= 0) { + set_program_uniform(ctx, &shProg->VertexProgram->Base, + loc, type, count, elems, values); + } } - for (k = 0; k < count; k++) { - GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k]; - if (type == GL_INT || - type == GL_INT_VEC2 || - type == GL_INT_VEC3 || - type == GL_INT_VEC4) { - const GLint *iValues = ((const GLint *) values) + k * elems; - for (i = 0; i < elems; i++) { - uniformVal[i] = (GLfloat) iValues[i]; - } + if (shProg->FragmentProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].FragPos; + if (loc >= 0) { + set_program_uniform(ctx, &shProg->FragmentProgram->Base, + loc, type, count, elems, values); } - else { - const GLfloat *fValues = ((const GLfloat *) values) + k * elems; - for (i = 0; i < elems; i++) { - uniformVal[i] = fValues[i]; + } +} + + +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 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. So, the loops below look a little funny. + * XXX could optimize this a bit... + */ + + /* loop over matrices */ + for (mat = 0; mat < count; mat++) { + + /* each matrix: */ + for (col = 0; col < cols; col++) { + GLfloat *v = program->Parameters->ParameterValues[dst]; + for (row = 0; row < rows; row++) { + if (transpose) { + v[row] = values[src + row * cols + col]; + } + else { + v[row] = values[src + col * rows + row]; + } } + dst++; } - } - if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) { - if (shProg->VertexProgram) - _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base); - if (shProg->FragmentProgram) - _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base); - FLUSH_VERTICES(ctx, _NEW_TEXTURE); + src += rows * cols; /* next matrix */ } } /** * Called by ctx->Driver.UniformMatrix(). + * Note: cols=2, rows=4 ==> array[2] of vec4 */ -void +static void _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, GLenum matrixType, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + if (!shProg || !shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(program not linked)"); return; } - if (location < 0 || location >= shProg->Uniforms->NumParameters) { + + 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, "glUniformMatrix(location)"); return; } @@ -1173,45 +1532,41 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, FLUSH_VERTICES(ctx, _NEW_PROGRAM); - /* - * Note: the _columns_ of a matrix are stored in program registers, not - * the rows. - */ - /* XXXX need to test 3x3 and 2x2 matrices... */ - if (transpose) { - GLuint row, col; - for (col = 0; col < cols; col++) { - GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; - for (row = 0; row < rows; row++) { - v[row] = values[row * cols + col]; - } + if (shProg->VertexProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].VertPos; + if (loc >= 0) { + set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base, + loc, count, rows, cols, transpose, values); } } - else { - GLuint row, col; - for (col = 0; col < cols; col++) { - GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; - for (row = 0; row < rows; row++) { - v[row] = values[col * rows + row]; - } + + if (shProg->FragmentProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].FragPos; + if (loc >= 0) { + set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base, + loc, count, rows, cols, transpose, values); } } } -void +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, @@ -1224,4 +1579,44 @@ _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; +} + + +/** + * Plug in Mesa's GLSL functions into the device driver function table. + */ +void +_mesa_init_glsl_driver_functions(struct dd_function_table *driver) +{ + driver->AttachShader = _mesa_attach_shader; + driver->BindAttribLocation = _mesa_bind_attrib_location; + driver->CompileShader = _mesa_compile_shader; + driver->CreateProgram = _mesa_create_program; + driver->CreateShader = _mesa_create_shader; + driver->DeleteProgram2 = _mesa_delete_program2; + driver->DeleteShader = _mesa_delete_shader; + driver->DetachShader = _mesa_detach_shader; + driver->GetActiveAttrib = _mesa_get_active_attrib; + driver->GetActiveUniform = _mesa_get_active_uniform; + driver->GetAttachedShaders = _mesa_get_attached_shaders; + driver->GetAttribLocation = _mesa_get_attrib_location; + driver->GetHandle = _mesa_get_handle; + driver->GetProgramiv = _mesa_get_programiv; + driver->GetProgramInfoLog = _mesa_get_program_info_log; + driver->GetShaderiv = _mesa_get_shaderiv; + 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; + driver->LinkProgram = _mesa_link_program; + driver->ShaderSource = _mesa_shader_source; + driver->Uniform = _mesa_uniform; + driver->UniformMatrix = _mesa_uniform_matrix; + driver->UseProgram = _mesa_use_program; + driver->ValidateProgram = _mesa_validate_program; }