diff options
Diffstat (limited to 'src/mesa/main')
27 files changed, 6770 insertions, 1295 deletions
diff --git a/src/mesa/main/api_exec.c b/src/mesa/main/api_exec.c index 06df97dfede..37d1ba45060 100644 --- a/src/mesa/main/api_exec.c +++ b/src/mesa/main/api_exec.c @@ -34,9 +34,9 @@ #include "api_loopback.h" #include "api_exec.h" #if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program -#include "shader/arbprogram.h" +#include "arbprogram.h" #endif -#include "shader/atifragshader.h" +#include "atifragshader.h" #include "attrib.h" #include "blend.h" #if FEATURE_ARB_vertex_buffer_object @@ -92,13 +92,14 @@ #include "varray.h" #include "viewport.h" #if FEATURE_NV_vertex_program -#include "shader/nvprogram.h" +#include "nvprogram.h" #endif #if FEATURE_NV_fragment_program -#include "shader/nvprogram.h" +#include "nvprogram.h" #endif #if FEATURE_ARB_shader_objects -#include "shaders.h" +#include "shaderapi.h" +#include "uniforms.h" #endif #if FEATURE_ARB_sync #include "syncobj.h" @@ -347,6 +348,7 @@ _mesa_create_exec_table(void) #if FEATURE_ARB_shader_objects _mesa_init_shader_dispatch(exec); + _mesa_init_shader_uniform_dispatch(exec); #endif /* 2. GL_EXT_blend_color */ diff --git a/src/mesa/main/arbprogram.c b/src/mesa/main/arbprogram.c new file mode 100644 index 00000000000..26d781954ed --- /dev/null +++ b/src/mesa/main/arbprogram.c @@ -0,0 +1,940 @@ +/* + * Mesa 3-D graphics library + * Version: 7.0 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file arbprogram.c + * ARB_vertex/fragment_program state management functions. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "main/arbprogram.h" +#include "program/arbprogparse.h" +#include "program/nvfragparse.h" +#include "program/nvvertparse.h" +#include "program/program.h" + + + +/** + * Mixing ARB and NV vertex/fragment programs can be tricky. + * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV + * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV + * The two different fragment program targets are supposed to be compatible + * to some extent (see GL_ARB_fragment_program spec). + * This function does the compatibility check. + */ +static GLboolean +compatible_program_targets(GLenum t1, GLenum t2) +{ + if (t1 == t2) + return GL_TRUE; + if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV) + return GL_TRUE; + if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB) + return GL_TRUE; + return GL_FALSE; +} + + +/** + * Bind a program (make it current) + * \note Called from the GL API dispatcher by both glBindProgramNV + * and glBindProgramARB. + */ +void GLAPIENTRY +_mesa_BindProgram(GLenum target, GLuint id) +{ + struct gl_program *curProg, *newProg; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* Error-check target and get curProg */ + if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */ + (ctx->Extensions.NV_vertex_program || + ctx->Extensions.ARB_vertex_program)) { + curProg = &ctx->VertexProgram.Current->Base; + } + else if ((target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) || + (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program)) { + curProg = &ctx->FragmentProgram.Current->Base; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); + return; + } + + /* + * Get pointer to new program to bind. + * NOTE: binding to a non-existant program is not an error. + * That's supposed to be caught in glBegin. + */ + if (id == 0) { + /* Bind a default program */ + newProg = NULL; + if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */ + newProg = &ctx->Shared->DefaultVertexProgram->Base; + else + newProg = &ctx->Shared->DefaultFragmentProgram->Base; + } + else { + /* Bind a user program */ + newProg = _mesa_lookup_program(ctx, id); + if (!newProg || newProg == &_mesa_DummyProgram) { + /* allocate a new program now */ + newProg = ctx->Driver.NewProgram(ctx, target, id); + if (!newProg) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, newProg); + } + else if (!compatible_program_targets(newProg->Target, target)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindProgramNV/ARB(target mismatch)"); + return; + } + } + + /** All error checking is complete now **/ + + if (curProg->Id == id) { + /* binding same program - no change */ + return; + } + + /* signal new program (and its new constants) */ + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + + /* bind newProg */ + if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */ + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + (struct gl_vertex_program *) newProg); + } + else if (target == GL_FRAGMENT_PROGRAM_NV || + target == GL_FRAGMENT_PROGRAM_ARB) { + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + (struct gl_fragment_program *) newProg); + } + + /* Never null pointers */ + ASSERT(ctx->VertexProgram.Current); + ASSERT(ctx->FragmentProgram.Current); + + if (ctx->Driver.BindProgram) + ctx->Driver.BindProgram(ctx, target, newProg); +} + + +/** + * Delete a list of programs. + * \note Not compiled into display lists. + * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. + */ +void GLAPIENTRY +_mesa_DeletePrograms(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (n < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); + return; + } + + for (i = 0; i < n; i++) { + if (ids[i] != 0) { + struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); + if (prog == &_mesa_DummyProgram) { + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); + } + else if (prog) { + /* Unbind program if necessary */ + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ + case GL_VERTEX_STATE_PROGRAM_NV: + if (ctx->VertexProgram.Current && + ctx->VertexProgram.Current->Base.Id == ids[i]) { + /* unbind this currently bound program */ + _mesa_BindProgram(prog->Target, 0); + } + break; + case GL_FRAGMENT_PROGRAM_NV: + case GL_FRAGMENT_PROGRAM_ARB: + if (ctx->FragmentProgram.Current && + ctx->FragmentProgram.Current->Base.Id == ids[i]) { + /* unbind this currently bound program */ + _mesa_BindProgram(prog->Target, 0); + } + break; + default: + _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); + return; + } + /* The ID is immediately available for re-use now */ + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); + _mesa_reference_program(ctx, &prog, NULL); + } + } + } +} + + +/** + * Generate a list of new program identifiers. + * \note Not compiled into display lists. + * \note Called by both glGenProgramsNV and glGenProgramsARB. + */ +void GLAPIENTRY +_mesa_GenPrograms(GLsizei n, GLuint *ids) +{ + GLuint first; + GLuint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); + return; + } + + if (!ids) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); + + /* Insert pointer to dummy program as placeholder */ + for (i = 0; i < (GLuint) n; i++) { + _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram); + } + + /* Return the program names */ + for (i = 0; i < (GLuint) n; i++) { + ids[i] = first + i; + } +} + + +/** + * Determine if id names a vertex or fragment program. + * \note Not compiled into display lists. + * \note Called from both glIsProgramNV and glIsProgramARB. + * \param id is the program identifier + * \return GL_TRUE if id is a program, else GL_FALSE. + */ +GLboolean GLAPIENTRY +_mesa_IsProgramARB(GLuint id) +{ + struct gl_program *prog = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (id == 0) + return GL_FALSE; + + prog = _mesa_lookup_program(ctx, id); + if (prog && (prog != &_mesa_DummyProgram)) + return GL_TRUE; + else + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, + const GLvoid *string) +{ + struct gl_program *base; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (!ctx->Extensions.ARB_vertex_program + && !ctx->Extensions.ARB_fragment_program) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()"); + return; + } + + if (format != GL_PROGRAM_FORMAT_ASCII_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)"); + return; + } + + /* The first couple cases are complicated. The same enum value is used for + * ARB and NV vertex programs. If the target is a vertex program, parse it + * using the ARB grammar if the string starts with "!!ARB" or if + * NV_vertex_program is not supported. + */ + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program + && ((strncmp(string, "!!ARB", 5) == 0) + || !ctx->Extensions.NV_vertex_program)) { + struct gl_vertex_program *prog = ctx->VertexProgram.Current; + _mesa_parse_arb_vertex_program(ctx, target, string, len, prog); + + base = & prog->Base; + } + else if ((target == GL_VERTEX_PROGRAM_ARB + || target == GL_VERTEX_STATE_PROGRAM_NV) + && ctx->Extensions.NV_vertex_program) { + struct gl_vertex_program *prog = ctx->VertexProgram.Current; + _mesa_parse_nv_vertex_program(ctx, target, string, len, prog); + + base = & prog->Base; + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + struct gl_fragment_program *prog = ctx->FragmentProgram.Current; + _mesa_parse_arb_fragment_program(ctx, target, string, len, prog); + + base = & prog->Base; + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + struct gl_fragment_program *prog = ctx->FragmentProgram.Current; + _mesa_parse_nv_fragment_program(ctx, target, string, len, prog); + + base = & prog->Base; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)"); + return; + } + + if (ctx->Program.ErrorPos == -1) { + /* finally, give the program to the driver for translation/checking */ + if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glProgramStringARB(rejected by driver"); + } + } +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterdNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, + (GLfloat) z, (GLfloat) w); +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterdvNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params) +{ + _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0], + (GLfloat) params[1], (GLfloat) params[2], + (GLfloat) params[3]); +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterfNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); + return; + } + ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w); + } + else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */ + && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) { + if (index >= ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); + return; + } + ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)"); + return; + } +} + + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterfvNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)"); + return; + } + memcpy(ctx->FragmentProgram.Parameters[index], params, + 4 * sizeof(GLfloat)); + } + else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */ + && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) { + if (index >= ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)"); + return; + } + memcpy(ctx->VertexProgram.Parameters[index], params, + 4 * sizeof(GLfloat)); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter4fv(target)"); + return; + } +} + + +void GLAPIENTRY +_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat * dest; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (count <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)"); + } + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); + return; + } + dest = ctx->FragmentProgram.Parameters[index]; + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); + return; + } + dest = ctx->VertexProgram.Parameters[index]; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)"); + return; + } + + memcpy(dest, params, count * 4 * sizeof(GLfloat)); +} + + +void GLAPIENTRY +_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, + GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat fparams[4]; + + _mesa_GetProgramEnvParameterfvARB(target, index, fparams); + if (ctx->ErrorValue == GL_NO_ERROR) { + params[0] = fparams[0]; + params[1] = fparams[1]; + params[2] = fparams[2]; + params[3] = fparams[3]; + } +} + + +void GLAPIENTRY +_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, + GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); + return; + } + COPY_4V(params, ctx->FragmentProgram.Parameters[index]); + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if (index >= ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); + return; + } + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)"); + return; + } +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *prog; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if ((target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) || + (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program)) { + if (index >= ctx->Const.FragmentProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); + return; + } + prog = &(ctx->FragmentProgram.Current->Base); + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if (index >= ctx->Const.VertexProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); + return; + } + prog = &(ctx->VertexProgram.Current->Base); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB"); + return; + } + + ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); + prog->LocalParams[index][0] = x; + prog->LocalParams[index][1] = y; + prog->LocalParams[index][2] = z; + prog->LocalParams[index][3] = w; +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params) +{ + _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1], + params[2], params[3]); +} + + +void GLAPIENTRY +_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat *dest; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (count <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)"); + } + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); + return; + } + dest = ctx->FragmentProgram.Current->Base.LocalParams[index]; + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); + return; + } + dest = ctx->VertexProgram.Current->Base.LocalParams[index]; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)"); + return; + } + + memcpy(dest, params, count * 4 * sizeof(GLfloat)); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, + GLdouble z, GLdouble w) +{ + _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, + (GLfloat) z, (GLfloat) w); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params) +{ + _mesa_ProgramLocalParameter4fARB(target, index, + (GLfloat) params[0], (GLfloat) params[1], + (GLfloat) params[2], (GLfloat) params[3]); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, + GLfloat *params) +{ + const struct gl_program *prog; + GLuint maxParams; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + prog = &(ctx->VertexProgram.Current->Base); + maxParams = ctx->Const.VertexProgram.MaxLocalParams; + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + maxParams = ctx->Const.FragmentProgram.MaxLocalParams; + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetProgramLocalParameterARB(target)"); + return; + } + + if (index >= maxParams) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramLocalParameterARB(index)"); + return; + } + + ASSERT(prog); + ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); + COPY_4V(params, prog->LocalParams[index]); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, + GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat floatParams[4]; + ASSIGN_4V(floatParams, 0.0F, 0.0F, 0.0F, 0.0F); + _mesa_GetProgramLocalParameterfvARB(target, index, floatParams); + if (ctx->ErrorValue == GL_NO_ERROR) { + COPY_4V(params, floatParams); + } +} + + +void GLAPIENTRY +_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params) +{ + const struct gl_program_constants *limits; + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + prog = &(ctx->VertexProgram.Current->Base); + limits = &ctx->Const.VertexProgram; + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + limits = &ctx->Const.FragmentProgram; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)"); + return; + } + + ASSERT(prog); + ASSERT(limits); + + /* Queries supported for both vertex and fragment programs */ + switch (pname) { + case GL_PROGRAM_LENGTH_ARB: + *params + = prog->String ? (GLint) strlen((char *) prog->String) : 0; + return; + case GL_PROGRAM_FORMAT_ARB: + *params = prog->Format; + return; + case GL_PROGRAM_BINDING_ARB: + *params = prog->Id; + return; + case GL_PROGRAM_INSTRUCTIONS_ARB: + *params = prog->NumInstructions; + return; + case GL_MAX_PROGRAM_INSTRUCTIONS_ARB: + *params = limits->MaxInstructions; + return; + case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB: + *params = prog->NumNativeInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB: + *params = limits->MaxNativeInstructions; + return; + case GL_PROGRAM_TEMPORARIES_ARB: + *params = prog->NumTemporaries; + return; + case GL_MAX_PROGRAM_TEMPORARIES_ARB: + *params = limits->MaxTemps; + return; + case GL_PROGRAM_NATIVE_TEMPORARIES_ARB: + *params = prog->NumNativeTemporaries; + return; + case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB: + *params = limits->MaxNativeTemps; + return; + case GL_PROGRAM_PARAMETERS_ARB: + *params = prog->NumParameters; + return; + case GL_MAX_PROGRAM_PARAMETERS_ARB: + *params = limits->MaxParameters; + return; + case GL_PROGRAM_NATIVE_PARAMETERS_ARB: + *params = prog->NumNativeParameters; + return; + case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB: + *params = limits->MaxNativeParameters; + return; + case GL_PROGRAM_ATTRIBS_ARB: + *params = prog->NumAttributes; + return; + case GL_MAX_PROGRAM_ATTRIBS_ARB: + *params = limits->MaxAttribs; + return; + case GL_PROGRAM_NATIVE_ATTRIBS_ARB: + *params = prog->NumNativeAttributes; + return; + case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB: + *params = limits->MaxNativeAttribs; + return; + case GL_PROGRAM_ADDRESS_REGISTERS_ARB: + *params = prog->NumAddressRegs; + return; + case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB: + *params = limits->MaxAddressRegs; + return; + case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: + *params = prog->NumNativeAddressRegs; + return; + case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: + *params = limits->MaxNativeAddressRegs; + return; + case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB: + *params = limits->MaxLocalParams; + return; + case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB: + *params = limits->MaxEnvParams; + return; + case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB: + /* + * XXX we may not really need a driver callback here. + * If the number of native instructions, registers, etc. used + * are all below the maximums, we could return true. + * The spec says that even if this query returns true, there's + * no guarantee that the program will run in hardware. + */ + if (prog->Id == 0) { + /* default/null program */ + *params = GL_FALSE; + } + else if (ctx->Driver.IsProgramNative) { + /* ask the driver */ + *params = ctx->Driver.IsProgramNative( ctx, target, prog ); + } + else { + /* probably running in software */ + *params = GL_TRUE; + } + return; + default: + /* continue with fragment-program only queries below */ + break; + } + + /* + * The following apply to fragment programs only (at this time) + */ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + const struct gl_fragment_program *fp = ctx->FragmentProgram.Current; + switch (pname) { + case GL_PROGRAM_ALU_INSTRUCTIONS_ARB: + *params = fp->Base.NumNativeAluInstructions; + return; + case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: + *params = fp->Base.NumAluInstructions; + return; + case GL_PROGRAM_TEX_INSTRUCTIONS_ARB: + *params = fp->Base.NumTexInstructions; + return; + case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: + *params = fp->Base.NumNativeTexInstructions; + return; + case GL_PROGRAM_TEX_INDIRECTIONS_ARB: + *params = fp->Base.NumTexIndirections; + return; + case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: + *params = fp->Base.NumNativeTexIndirections; + return; + case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB: + *params = limits->MaxAluInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: + *params = limits->MaxNativeAluInstructions; + return; + case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB: + *params = limits->MaxTexInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: + *params = limits->MaxNativeTexInstructions; + return; + case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: + *params = limits->MaxTexIndirections; + return; + case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: + *params = limits->MaxNativeTexIndirections; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); + return; + } + } else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string) +{ + const struct gl_program *prog; + char *dst = (char *) string; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB) { + prog = &(ctx->VertexProgram.Current->Base); + } + else if (target == GL_FRAGMENT_PROGRAM_ARB) { + prog = &(ctx->FragmentProgram.Current->Base); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)"); + return; + } + + ASSERT(prog); + + if (pname != GL_PROGRAM_STRING_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)"); + return; + } + + if (prog->String) + memcpy(dst, prog->String, strlen((char *) prog->String)); + else + *dst = '\0'; +} diff --git a/src/mesa/main/arbprogram.h b/src/mesa/main/arbprogram.h new file mode 100644 index 00000000000..787ffd62f4b --- /dev/null +++ b/src/mesa/main/arbprogram.h @@ -0,0 +1,132 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef ARBPROGRAM_H +#define ARBPROGRAM_H + + +#include "compiler.h" +#include "glheader.h" + + +extern void GLAPIENTRY +_mesa_BindProgram(GLenum target, GLuint id); + +extern void GLAPIENTRY +_mesa_DeletePrograms(GLsizei n, const GLuint *ids); + +extern void GLAPIENTRY +_mesa_GenPrograms(GLsizei n, GLuint *ids); + + +extern GLboolean GLAPIENTRY +_mesa_IsProgramARB(GLuint id); + + +extern void GLAPIENTRY +_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, + const GLvoid *string); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, GLdouble z, GLdouble w); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, + GLdouble z, GLdouble w); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, + GLdouble *params); + + +extern void GLAPIENTRY +_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, + GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, + GLdouble *params); + + +extern void GLAPIENTRY +_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, + GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params); + + +extern void GLAPIENTRY +_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string); + + +#endif diff --git a/src/mesa/main/atifragshader.c b/src/mesa/main/atifragshader.c new file mode 100644 index 00000000000..550f50b7a00 --- /dev/null +++ b/src/mesa/main/atifragshader.c @@ -0,0 +1,794 @@ +/** + * \file atifragshader.c + * \author David Airlie + * Copyright (C) 2004 David Airlie All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/enums.h" +#include "main/mtypes.h" +#include "main/dispatch.h" +#include "main/atifragshader.h" + +#if FEATURE_ATI_fragment_shader + +#define MESA_DEBUG_ATI_FS 0 + +static struct ati_fragment_shader DummyShader; + + +void +_mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp) +{ + SET_GenFragmentShadersATI(disp, _mesa_GenFragmentShadersATI); + SET_BindFragmentShaderATI(disp, _mesa_BindFragmentShaderATI); + SET_DeleteFragmentShaderATI(disp, _mesa_DeleteFragmentShaderATI); + SET_BeginFragmentShaderATI(disp, _mesa_BeginFragmentShaderATI); + SET_EndFragmentShaderATI(disp, _mesa_EndFragmentShaderATI); + SET_PassTexCoordATI(disp, _mesa_PassTexCoordATI); + SET_SampleMapATI(disp, _mesa_SampleMapATI); + SET_ColorFragmentOp1ATI(disp, _mesa_ColorFragmentOp1ATI); + SET_ColorFragmentOp2ATI(disp, _mesa_ColorFragmentOp2ATI); + SET_ColorFragmentOp3ATI(disp, _mesa_ColorFragmentOp3ATI); + SET_AlphaFragmentOp1ATI(disp, _mesa_AlphaFragmentOp1ATI); + SET_AlphaFragmentOp2ATI(disp, _mesa_AlphaFragmentOp2ATI); + SET_AlphaFragmentOp3ATI(disp, _mesa_AlphaFragmentOp3ATI); + SET_SetFragmentShaderConstantATI(disp, _mesa_SetFragmentShaderConstantATI); +} + + +/** + * Allocate and initialize a new ATI fragment shader object. + */ +struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id) +{ + struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader); + (void) ctx; + if (s) { + s->Id = id; + s->RefCount = 1; + } + return s; +} + + +/** + * Delete the given ati fragment shader + */ +void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, struct ati_fragment_shader *s) +{ + GLuint i; + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (s->Instructions[i]) + free(s->Instructions[i]); + if (s->SetupInst[i]) + free(s->SetupInst[i]); + } + free(s); +} + + + +static void +new_arith_inst(struct ati_fragment_shader *prog) +{ +/* set "default" instruction as not all may get defined. + there is no specified way to express a nop with ati fragment shaders we use + GL_NONE as the op enum and just set some params to 0 - so nothing to do here */ + prog->numArithInstr[prog->cur_pass >> 1]++; +} + +static void +new_tex_inst(struct ati_fragment_shader *prog) +{ +} + +static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype) +{ + if (optype == curProg->last_optype) { + curProg->last_optype = 1; + } +} + +#if MESA_DEBUG_ATI_FS +static char * +create_dst_mod_str(GLuint mod) +{ + static char ret_str[1024]; + + memset(ret_str, 0, 1024); + if (mod & GL_2X_BIT_ATI) + strncat(ret_str, "|2X", 1024); + + if (mod & GL_4X_BIT_ATI) + strncat(ret_str, "|4X", 1024); + + if (mod & GL_8X_BIT_ATI) + strncat(ret_str, "|8X", 1024); + if (mod & GL_HALF_BIT_ATI) + strncat(ret_str, "|HA", 1024); + if (mod & GL_QUARTER_BIT_ATI) + strncat(ret_str, "|QU", 1024); + if (mod & GL_EIGHTH_BIT_ATI) + strncat(ret_str, "|EI", 1024); + + if (mod & GL_SATURATE_BIT_ATI) + strncat(ret_str, "|SAT", 1024); + + if (strlen(ret_str) == 0) + strncat(ret_str, "NONE", 1024); + return ret_str; +} + +static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI", + "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" }; + +static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + char *op_name; + + op_name = atifs_ops[(arg_count-1)+(optype?3:0)]; + + fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op), + _mesa_lookup_enum_by_nr(dst)); + if (!optype) + fprintf(stderr, ", %d", dstMask); + + fprintf(stderr, ", %s", create_dst_mod_str(dstMod)); + + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1), + _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod); + if (arg_count>1) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2), + _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod); + if (arg_count>2) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3), + _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod); + + fprintf(stderr,")\n"); + +} +#endif + +static int check_arith_arg(struct ati_fragment_shader *curProg, + GLuint optype, GLuint arg, GLuint argRep) +{ + GET_CURRENT_CONTEXT(ctx); + + if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) && + ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) && + (arg != GL_ZERO) && (arg != GL_ONE) && + (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((curProg->cur_pass == 1) && + ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) { + curProg->interpinp1 = GL_TRUE; + } + return 1; +} + +GLuint GLAPIENTRY +_mesa_GenFragmentShadersATI(GLuint range) +{ + GLuint first; + GLuint i; + GET_CURRENT_CONTEXT(ctx); + + if (range == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)"); + return 0; + } + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)"); + return 0; + } + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range); + for (i = 0; i < range; i++) { + _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader); + } + + return first; +} + +void GLAPIENTRY +_mesa_BindFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct ati_fragment_shader *newProg; + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (curProg->Id == id) { + return; + } + + /* unbind current */ + if (curProg->Id != 0) { + curProg->RefCount--; + if (curProg->RefCount <= 0) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + } + + /* find new shader */ + if (id == 0) { + newProg = ctx->Shared->DefaultFragmentShader; + } + else { + newProg = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (!newProg || newProg == &DummyShader) { + /* allocate a new program now */ + newProg = _mesa_new_ati_fragment_shader(ctx, id); + if (!newProg) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI"); + return; + } + _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg); + } + + } + + /* do actual bind */ + ctx->ATIFragmentShader.Current = newProg; + + ASSERT(ctx->ATIFragmentShader.Current); + if (newProg) + newProg->RefCount++; + + /*if (ctx->Driver.BindProgram) + ctx->Driver.BindProgram(ctx, target, prog); */ +} + +void GLAPIENTRY +_mesa_DeleteFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)"); + return; + } + + if (id != 0) { + struct ati_fragment_shader *prog = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (prog == &DummyShader) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + else if (prog) { + if (ctx->ATIFragmentShader.Current && + ctx->ATIFragmentShader.Current->Id == id) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_BindFragmentShaderATI(0); + } + } + + /* The ID is immediately available for re-use now */ + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + if (prog) { + prog->RefCount--; + if (prog->RefCount <= 0) { + free(prog); + } + } + } +} + + +void GLAPIENTRY +_mesa_BeginFragmentShaderATI(void) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + /* if the shader was already defined free instructions and get new ones + (or, could use the same mem but would need to reinitialize) */ + /* no idea if it's allowed to redefine a shader */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (ctx->ATIFragmentShader.Current->Instructions[i]) + free(ctx->ATIFragmentShader.Current->Instructions[i]); + if (ctx->ATIFragmentShader.Current->SetupInst[i]) + free(ctx->ATIFragmentShader.Current->SetupInst[i]); + } + + /* malloc the instructions here - not sure if the best place but its + a start */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + ctx->ATIFragmentShader.Current->Instructions[i] = + (struct atifs_instruction *) + calloc(1, sizeof(struct atifs_instruction) * + (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI)); + ctx->ATIFragmentShader.Current->SetupInst[i] = + (struct atifs_setupinst *) + calloc(1, sizeof(struct atifs_setupinst) * + (MAX_NUM_FRAGMENT_REGISTERS_ATI)); + } + +/* can't rely on calloc for initialization as it's possible to redefine a shader (?) */ + ctx->ATIFragmentShader.Current->LocalConstDef = 0; + ctx->ATIFragmentShader.Current->numArithInstr[0] = 0; + ctx->ATIFragmentShader.Current->numArithInstr[1] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[0] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[1] = 0; + ctx->ATIFragmentShader.Current->NumPasses = 0; + ctx->ATIFragmentShader.Current->cur_pass = 0; + ctx->ATIFragmentShader.Current->last_optype = 0; + ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE; + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + ctx->ATIFragmentShader.Current->swizzlerq = 0; + ctx->ATIFragmentShader.Compiling = 1; +} + +void GLAPIENTRY +_mesa_EndFragmentShaderATI(void) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; +#if MESA_DEBUG_ATI_FS + GLint i, j; +#endif + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)"); + return; + } + if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)"); + /* according to spec, DON'T return here */ + } + + match_pair_inst(curProg, 0); + ctx->ATIFragmentShader.Compiling = 0; + ctx->ATIFragmentShader.Current->isValid = GL_TRUE; + if ((ctx->ATIFragmentShader.Current->cur_pass == 0) || + (ctx->ATIFragmentShader.Current->cur_pass == 2)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)"); + } + if (ctx->ATIFragmentShader.Current->cur_pass > 1) + ctx->ATIFragmentShader.Current->NumPasses = 2; + else + ctx->ATIFragmentShader.Current->NumPasses = 1; + + ctx->ATIFragmentShader.Current->cur_pass = 0; + +#if MESA_DEBUG_ATI_FS + for (j = 0; j < MAX_NUM_PASSES_ATI; j++) { + for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) { + GLuint op = curProg->SetupInst[j][i].Opcode; + const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0"; + GLuint src = curProg->SetupInst[j][i].src; + GLuint swizzle = curProg->SetupInst[j][i].swizzle; + fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src, + swizzle); + } + for (i = 0; i < curProg->numArithInstr[j]; i++) { + GLuint op0 = curProg->Instructions[j][i].Opcode[0]; + GLuint op1 = curProg->Instructions[j][i].Opcode[1]; + const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0"; + const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0"; + GLuint count0 = curProg->Instructions[j][i].ArgCount[0]; + GLuint count1 = curProg->Instructions[j][i].ArgCount[1]; + fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0, + op1, op1_enum, count1); + } + } +#endif + + if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) { + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + /* XXX is this the right error? */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndFragmentShaderATI(driver rejected shader)"); + } +} + +void GLAPIENTRY +_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)"); + return; + } + if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) && + ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) || + ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)"); + return; + } + if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)"); + return; + } + if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } + if (coord <= GL_TEXTURE7_ARB) { + GLuint tmp = coord - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP; + curI->src = coord; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +void GLAPIENTRY +_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)"); + return; + } + if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) && + ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) || + ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + /* is this texture5 or texture7? spec is a bit unclear there */ + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)"); + return; + } + if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)"); + return; + } + if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } + if (interp <= GL_TEXTURE7_ARB) { + GLuint tmp = interp - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP; + curI->src = interp; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +static void +_mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + GLint ci; + struct atifs_instruction *curI; + GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)"); + return; + } + + if (curProg->cur_pass==0) + curProg->cur_pass=1; + + else if (curProg->cur_pass==2) + curProg->cur_pass=3; + + /* decide whether this is a new instruction or not ... all color instructions are new, + and alpha instructions might also be new if there was no preceding color inst */ + if ((optype == 0) || (curProg->last_optype == optype)) { + if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)"); + return; + } + /* easier to do that here slight side effect invalid instr will still be inserted as nops */ + match_pair_inst(curProg, optype); + new_arith_inst(curProg); + } + curProg->last_optype = optype; + ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1; + + /* add the instructions */ + curI = &curProg->Instructions[curProg->cur_pass >> 1][ci]; + + /* error checking */ + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)"); + return; + } + if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) && + (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) && + (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) && + (modtemp != GL_EIGHTH_BIT_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp); + return; + } + /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */ + if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)"); + return; + } + if (optype == 1) { + if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) || + ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) || + ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) || + ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)"); + return; + } + } + if ((op == GL_DOT4_ATI) && + (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) || + (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + } + + if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) { + return; + } + if (arg2) { + if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) { + return; + } + } + if (arg3) { + if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) { + return; + } + if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) && + (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) && + (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) && + (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)"); + return; + } + } + + /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */ + + curI->Opcode[optype] = op; + curI->SrcReg[optype][0].Index = arg1; + curI->SrcReg[optype][0].argRep = arg1Rep; + curI->SrcReg[optype][0].argMod = arg1Mod; + curI->ArgCount[optype] = arg_count; + + if (arg2) { + curI->SrcReg[optype][1].Index = arg2; + curI->SrcReg[optype][1].argRep = arg2Rep; + curI->SrcReg[optype][1].argMod = arg2Mod; + } + + if (arg3) { + curI->SrcReg[optype][2].Index = arg3; + curI->SrcReg[optype][2].argRep = arg3Rep; + curI->SrcReg[optype][2].argMod = arg3Mod; + } + + curI->DstReg[optype].Index = dst; + curI->DstReg[optype].dstMod = dstMod; + curI->DstReg[optype].dstMask = dstMask; + +#if MESA_DEBUG_ATI_FS + debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +#endif + +} + +void GLAPIENTRY +_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, + GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, arg3, arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0, + 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, + arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value) +{ + GLuint dstindex; + GET_CURRENT_CONTEXT(ctx); + + if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) { + /* spec says nothing about what should happen here but we can't just segfault...*/ + _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)"); + return; + } + + dstindex = dst - GL_CON_0_ATI; + if (ctx->ATIFragmentShader.Compiling) { + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + COPY_4V(curProg->Constants[dstindex], value); + curProg->LocalConstDef |= 1 << dstindex; + } + else { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value); + } +} + +#endif /* FEATURE_ATI_fragment_shader */ diff --git a/src/mesa/main/atifragshader.h b/src/mesa/main/atifragshader.h new file mode 100644 index 00000000000..31c335ec815 --- /dev/null +++ b/src/mesa/main/atifragshader.h @@ -0,0 +1,149 @@ +/* + * Mesa 3-D graphics library ATI Fragment Shader + * + * Copyright (C) 2004 David Airlie All Rights Reserved. + * + */ + +#ifndef ATIFRAGSHADER_H +#define ATIFRAGSHADER_H + +#include "main/mtypes.h" + +#define MAX_NUM_INSTRUCTIONS_PER_PASS_ATI 8 +#define MAX_NUM_PASSES_ATI 2 +#define MAX_NUM_FRAGMENT_REGISTERS_ATI 6 + +struct ati_fs_opcode_st +{ + GLenum opcode; + GLint num_src_args; +}; + +extern struct ati_fs_opcode_st ati_fs_opcodes[]; + +struct atifragshader_src_register +{ + GLuint Index; + GLuint argRep; + GLuint argMod; +}; + +struct atifragshader_dst_register +{ + GLuint Index; + GLuint dstMod; + GLuint dstMask; +}; + +#define ATI_FRAGMENT_SHADER_COLOR_OP 0 +#define ATI_FRAGMENT_SHADER_ALPHA_OP 1 +#define ATI_FRAGMENT_SHADER_PASS_OP 2 +#define ATI_FRAGMENT_SHADER_SAMPLE_OP 3 + +/* two opcodes - one for color/one for alpha */ +/* up to three source registers for most ops */ +struct atifs_instruction +{ + GLenum Opcode[2]; + GLuint ArgCount[2]; + struct atifragshader_src_register SrcReg[2][3]; + struct atifragshader_dst_register DstReg[2]; +}; + +/* different from arithmetic shader instruction */ +struct atifs_setupinst +{ + GLenum Opcode; + GLuint src; + GLenum swizzle; +}; + + +#if FEATURE_ATI_fragment_shader + +extern void +_mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp); + +extern struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id); + +extern void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, + struct ati_fragment_shader *s); + + +extern GLuint GLAPIENTRY _mesa_GenFragmentShadersATI(GLuint range); + +extern void GLAPIENTRY _mesa_BindFragmentShaderATI(GLuint id); + +extern void GLAPIENTRY _mesa_DeleteFragmentShaderATI(GLuint id); + +extern void GLAPIENTRY _mesa_BeginFragmentShaderATI(void); + +extern void GLAPIENTRY _mesa_EndFragmentShaderATI(void); + +extern void GLAPIENTRY +_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle); + +extern void GLAPIENTRY +_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, + GLuint arg3Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod); + +extern void GLAPIENTRY +_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value); + +#else /* FEATURE_ATI_fragment_shader */ + +static INLINE void +_mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp) +{ +} + +static INLINE struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id) +{ + return NULL; +} + +static INLINE void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, + struct ati_fragment_shader *s) +{ +} + +#endif /* FEATURE_ATI_fragment_shader */ + +#endif /* ATIFRAGSHADER_H */ diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index e140a21b354..0afd77d3759 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -118,6 +118,7 @@ #include "remap.h" #include "scissor.h" #include "shared.h" +#include "shaderobj.h" #include "simple_list.h" #include "state.h" #include "stencil.h" @@ -129,9 +130,8 @@ #include "version.h" #include "viewport.h" #include "vtxfmt.h" -#include "shader/program.h" -#include "shader/prog_print.h" -#include "shader/shader_api.h" +#include "program/program.h" +#include "program/prog_print.h" #if _HAVE_FULL_GL #include "math/m_matrix.h" #endif diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 53e44533cb3..825073ca886 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -828,54 +828,12 @@ struct dd_function_table { * \name GLSL-related functions (ARB extensions and OpenGL 2.x) */ /*@{*/ - void (*AttachShader)(GLcontext *ctx, GLuint program, GLuint shader); - void (*BindAttribLocation)(GLcontext *ctx, GLuint program, GLuint index, - const GLcharARB *name); - void (*CompileShader)(GLcontext *ctx, GLuint shader); - GLuint (*CreateShader)(GLcontext *ctx, GLenum type); - GLuint (*CreateProgram)(GLcontext *ctx); - void (*DeleteProgram2)(GLcontext *ctx, GLuint program); - void (*DeleteShader)(GLcontext *ctx, GLuint shader); - void (*DetachShader)(GLcontext *ctx, GLuint program, GLuint shader); - void (*GetActiveAttrib)(GLcontext *ctx, GLuint program, GLuint index, - GLsizei maxLength, GLsizei * length, GLint * size, - GLenum * type, GLcharARB * name); - void (*GetActiveUniform)(GLcontext *ctx, GLuint program, GLuint index, - GLsizei maxLength, GLsizei *length, GLint *size, - GLenum *type, GLcharARB *name); - void (*GetAttachedShaders)(GLcontext *ctx, GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj); - GLint (*GetAttribLocation)(GLcontext *ctx, GLuint program, - const GLcharARB *name); - GLuint (*GetHandle)(GLcontext *ctx, GLenum pname); - void (*GetProgramiv)(GLcontext *ctx, GLuint program, - GLenum pname, GLint *params); - void (*GetProgramInfoLog)(GLcontext *ctx, GLuint program, GLsizei bufSize, - GLsizei *length, GLchar *infoLog); - void (*GetShaderiv)(GLcontext *ctx, GLuint shader, - GLenum pname, GLint *params); - void (*GetShaderInfoLog)(GLcontext *ctx, GLuint shader, GLsizei bufSize, - GLsizei *length, GLchar *infoLog); - void (*GetShaderSource)(GLcontext *ctx, GLuint shader, GLsizei maxLength, - GLsizei *length, GLcharARB *sourceOut); - void (*GetUniformfv)(GLcontext *ctx, GLuint program, GLint location, - GLfloat *params); - void (*GetUniformiv)(GLcontext *ctx, GLuint program, GLint location, - GLint *params); - GLint (*GetUniformLocation)(GLcontext *ctx, GLuint program, - const GLcharARB *name); - GLboolean (*IsProgram)(GLcontext *ctx, GLuint name); - GLboolean (*IsShader)(GLcontext *ctx, GLuint name); - void (*LinkProgram)(GLcontext *ctx, GLuint program); - void (*ShaderSource)(GLcontext *ctx, GLuint shader, const GLchar *source); - void (*Uniform)(GLcontext *ctx, GLint location, GLsizei count, - const GLvoid *values, GLenum type); - void (*UniformMatrix)(GLcontext *ctx, GLint cols, GLint rows, - GLint location, GLsizei count, - GLboolean transpose, const GLfloat *values); - void (*UseProgram)(GLcontext *ctx, GLuint program); - void (*ValidateProgram)(GLcontext *ctx, GLuint program); - /* XXX many more to come */ + struct gl_shader *(*NewShader)(GLcontext *ctx, GLuint name, GLenum type); + void (*DeleteShader)(GLcontext *ctx, struct gl_shader *shader); + struct gl_shader_program *(*NewShaderProgram)(GLcontext *ctx, GLuint name); + void (*DeleteShaderProgram)(GLcontext *ctx, + struct gl_shader_program *shProg); + void (*UseProgram)(GLcontext *ctx, struct gl_shader_program *shProg); /*@}*/ diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index 37a97513453..727414d529f 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -34,6 +34,9 @@ #include "api_arrayelt.h" #include "api_exec.h" #include "api_loopback.h" +#if FEATURE_ATI_fragment_shader +#include "atifragshader.h" +#endif #include "config.h" #include "mfeatures.h" #if FEATURE_ARB_vertex_buffer_object @@ -56,13 +59,10 @@ #include "mtypes.h" #include "varray.h" #if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program -#include "shader/arbprogram.h" +#include "arbprogram.h" #endif #if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program -#include "shader/nvprogram.h" -#endif -#if FEATURE_ATI_fragment_shader -#include "shader/atifragshader.h" +#include "nvprogram.h" #endif #include "math/m_matrix.h" diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c index 70ac47f36d7..92fec09bad0 100644 --- a/src/mesa/main/ffvertex_prog.c +++ b/src/mesa/main/ffvertex_prog.c @@ -38,12 +38,12 @@ #include "main/macros.h" #include "main/enums.h" #include "main/ffvertex_prog.h" -#include "shader/program.h" -#include "shader/prog_cache.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" +#include "program/program.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" /** Max of number of lights and texture coord units */ diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 03f2707f4f0..c121957aead 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -667,7 +667,7 @@ static const struct value_desc values[] = { { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, offsetof(GLcontext, Const.Max3DTextureLevels), NO_EXTRA }, - /* GL_ARB_fragment_shader/OES_standard_derivatives */ + /* GL_ARB_fragment_program/OES_standard_derivatives */ { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB, CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader }, #endif /* FEATURE_GL || FEATURE_ES2 */ diff --git a/src/mesa/main/nvprogram.c b/src/mesa/main/nvprogram.c new file mode 100644 index 00000000000..100ff2c4ab8 --- /dev/null +++ b/src/mesa/main/nvprogram.c @@ -0,0 +1,917 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvprogram.c + * NVIDIA vertex/fragment program state management functions. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/nvprogram.h" +#include "program/arbprogparse.h" +#include "program/nvfragparse.h" +#include "program/nvvertparse.h" +#include "program/program.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" + + + +/** + * Execute a vertex state program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) +{ + struct gl_vertex_program *vprog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id); + + if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); + return; + } + + _mesa_problem(ctx, "glExecuteProgramNV() not supported"); +} + + +/** + * Determine if a set of programs is resident in hardware. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +GLboolean GLAPIENTRY +_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, + GLboolean *residences) +{ + GLint i, j; + GLboolean allResident = GL_TRUE; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); + return GL_FALSE; + } + + for (i = 0; i < n; i++) { + const struct gl_program *prog; + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + if (prog->Resident) { + if (!allResident) + residences[i] = GL_TRUE; + } + else { + if (allResident) { + allResident = GL_FALSE; + for (j = 0; j < i; j++) + residences[j] = GL_TRUE; + } + residences[i] = GL_FALSE; + } + } + + return allResident; +} + + +/** + * Request that a set of programs be resident in hardware. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)"); + return; + } + + /* just error checking for now */ + for (i = 0; i < n; i++) { + struct gl_program *prog; + + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + /* XXX this is really a hardware thing we should hook out */ + prog->Resident = GL_TRUE; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, + GLenum pname, GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterfvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)"); + return; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, + GLenum pname, GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterdvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)"); + return; + } +} + + +/** + * Get a program attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV"); + return; + } + + switch (pname) { + case GL_PROGRAM_TARGET_NV: + *params = prog->Target; + return; + case GL_PROGRAM_LENGTH_NV: + *params = prog->String ?(GLint) strlen((char *) prog->String) : 0; + return; + case GL_PROGRAM_RESIDENT_NV: + *params = prog->Resident; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)"); + return; + } +} + + +/** + * Get the program source code. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (pname != GL_PROGRAM_STRING_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)"); + return; + } + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV"); + return; + } + + if (prog->String) { + memcpy(program, prog->String, strlen((char *) prog->String)); + } + else { + program[0] = 0; + } +} + + +/** + * Get matrix tracking information. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV + && ctx->Extensions.NV_vertex_program) { + GLuint i; + + if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)"); + return; + } + + i = address / 4; + + switch (pname) { + case GL_TRACK_MATRIX_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i]; + return; + case GL_TRACK_MATRIX_TRANSFORM_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i]; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } +} + + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribdvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = (GLfloat) array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = (GLfloat) array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = (GLfloat) array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribfvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribivNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + params[0] = (GLint) ctx->Current.Attrib[index][0]; + params[1] = (GLint) ctx->Current.Attrib[index][1]; + params[2] = (GLint) ctx->Current.Attrib[index][2]; + params[3] = (GLint) ctx->Current.Attrib[index][3]; + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: + params[0] = array->BufferObj->Name; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + + +/** + * Get a vertex array attribute pointer. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)"); + return; + } + + if (pname != GL_ATTRIB_ARRAY_POINTER_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)"); + return; + } + + *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr; +} + +void +_mesa_emit_nv_temp_initialization(GLcontext *ctx, + struct gl_program *program) +{ + struct prog_instruction *inst; + GLuint i; + + if (!ctx->Shader.EmitNVTempInitialization) + return; + + /* We'll swizzle up a zero temporary so we can use it for the + * ARL. + */ + if (program->NumTemporaries == 0) + program->NumTemporaries = 1; + + _mesa_insert_instructions(program, 0, program->NumTemporaries + 1); + + for (i = 0; i < program->NumTemporaries; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + inst->Opcode = OPCODE_SWZ; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = i; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO); + } + + inst = &program->Instructions[i]; + inst->Opcode = OPCODE_ARL; + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + + if (program->NumAddressRegs == 0) + program->NumAddressRegs = 1; +} + +void +_mesa_setup_nv_temporary_count(GLcontext *ctx, struct gl_program *program) +{ + GLuint i; + + program->NumTemporaries = 0; + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->DstReg.Index + 1); + } + if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[0].Index + 1); + } + if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[1].Index + 1); + } + if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2((GLint)program->NumTemporaries, + inst->SrcReg[2].Index + 1); + } + } +} + +/** + * Load/parse/compile a program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, + const GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.NV_vertex_program + && !ctx->Extensions.NV_fragment_program) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()"); + return; + } + + if (id == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); + return; + } + + if (len < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + prog = _mesa_lookup_program(ctx, id); + + if (prog && prog->Target != 0 && prog->Target != target) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); + return; + } + + if ((target == GL_VERTEX_PROGRAM_NV || + target == GL_VERTEX_STATE_PROGRAM_NV) + && ctx->Extensions.NV_vertex_program) { + struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; + if (!vprog || prog == &_mesa_DummyProgram) { + vprog = (struct gl_vertex_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!vprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, vprog); + } + + if (ctx->Extensions.ARB_vertex_program + && (strncmp((char *) program, "!!ARB", 5) == 0)) { + _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog); + } else { + _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); + } + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; + if (!fprog || prog == &_mesa_DummyProgram) { + fprog = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!fprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, fprog); + } + _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; + if (!fprog || prog == &_mesa_DummyProgram) { + fprog = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!fprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, fprog); + } + _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); + } +} + + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, + GLuint num, const GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLuint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV"); + return; + } + for (i = 0; i < num; i++) { + ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0]; + ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1]; + ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2]; + ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3]; + params += 4; + }; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV"); + return; + } +} + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, + GLuint num, const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLuint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV"); + return; + } + for (i = 0; i < num; i++) { + COPY_4V(ctx->VertexProgram.Parameters[index + i], params); + params += 4; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV"); + return; + } +} + + + +/** + * Setup tracking of matrices into program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_TrackMatrixNV(GLenum target, GLuint address, + GLenum matrix, GLenum transform) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + if (address & 0x3) { + /* addr must be multiple of four */ + _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)"); + return; + } + + switch (matrix) { + case GL_NONE: + case GL_MODELVIEW: + case GL_PROJECTION: + case GL_TEXTURE: + case GL_COLOR: + case GL_MODELVIEW_PROJECTION_NV: + case GL_MATRIX0_NV: + case GL_MATRIX1_NV: + case GL_MATRIX2_NV: + case GL_MATRIX3_NV: + case GL_MATRIX4_NV: + case GL_MATRIX5_NV: + case GL_MATRIX6_NV: + case GL_MATRIX7_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)"); + return; + } + + switch (transform) { + case GL_IDENTITY_NV: + case GL_INVERSE_NV: + case GL_TRANSPOSE_NV: + case GL_INVERSE_TRANSPOSE_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)"); + return; + } + + ctx->VertexProgram.TrackMatrix[address / 4] = matrix; + ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)"); + return; + } +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + GLfloat *v; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, + (char *) name); + if (v) { + v[0] = x; + v[1] = y; + v[2] = z; + v[3] = w; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, + const float v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y, + (GLfloat)z, (GLfloat)w); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, + const double v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, + (GLfloat)v[0], (GLfloat)v[1], + (GLfloat)v[2], (GLfloat)v[3]); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat *params) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + const GLfloat *v; + + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, + len, (char *) name); + if (v) { + params[0] = v[0]; + params[1] = v[1]; + params[2] = v[2]; + params[3] = v[3]; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble *params) +{ + GLfloat floatParams[4]; + _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams); + COPY_4V(params, floatParams); +} diff --git a/src/mesa/main/nvprogram.h b/src/mesa/main/nvprogram.h new file mode 100644 index 00000000000..8ee59661bd0 --- /dev/null +++ b/src/mesa/main/nvprogram.h @@ -0,0 +1,113 @@ +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVPROGRAM_H +#define NVPROGRAM_H + + +extern void GLAPIENTRY +_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params); + +extern GLboolean GLAPIENTRY +_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences); + +extern void GLAPIENTRY +_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids); + +extern void GLAPIENTRY +_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, GLenum pname, GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, GLenum pname, GLdouble *params); + +extern void GLAPIENTRY +_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program); + +extern void GLAPIENTRY +_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer); + +extern void GLAPIENTRY +_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program); + +extern void GLAPIENTRY +_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, GLuint num, const GLdouble *params); + +extern void GLAPIENTRY +_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, GLuint num, const GLfloat *params); + +extern void GLAPIENTRY +_mesa_TrackMatrixNV(GLenum target, GLuint address, GLenum matrix, GLenum transform); + + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, + const float v[]); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble x, GLdouble y, GLdouble z, GLdouble w); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, + const double v[]); + +extern void GLAPIENTRY +_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble *params); + +extern void +_mesa_setup_nv_temporary_count(GLcontext *ctx, struct gl_program *program); + +extern void +_mesa_emit_nv_temp_initialization(GLcontext *ctx, + struct gl_program *program); + +#endif diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c new file mode 100644 index 00000000000..0bd44154f26 --- /dev/null +++ b/src/mesa/main/shaderapi.c @@ -0,0 +1,1552 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file shaderapi.c + * \author Brian Paul + * + * Implementation of GLSL-related API functions. + * The glUniform* functions are in uniforms.c + * + * + * XXX things to do: + * 1. Check that the right error code is generated for all _mesa_error() calls. + * 2. Insert FLUSH_VERTICES calls in various places + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/dispatch.h" +#include "main/hash.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" +#include "slang/slang_compile.h" +#include "slang/slang_link.h" + + +/** Define this to enable shader substitution (see below) */ +#define SHADER_SUBST 0 + + +/** + * Return mask of GLSL_x flags by examining the MESA_GLSL env var. + */ +static GLbitfield +get_shader_flags(void) +{ + GLbitfield flags = 0x0; + const char *env = _mesa_getenv("MESA_GLSL"); + + if (env) { + if (strstr(env, "dump")) + flags |= GLSL_DUMP; + if (strstr(env, "log")) + flags |= GLSL_LOG; + if (strstr(env, "nopvert")) + flags |= GLSL_NOP_VERT; + if (strstr(env, "nopfrag")) + flags |= GLSL_NOP_FRAG; + if (strstr(env, "nopt")) + flags |= GLSL_NO_OPT; + else if (strstr(env, "opt")) + flags |= GLSL_OPT; + if (strstr(env, "uniform")) + flags |= GLSL_UNIFORMS; + if (strstr(env, "useprog")) + flags |= GLSL_USE_PROG; + } + + return flags; +} + + +/** + * Initialize context's shader state. + */ +void +_mesa_init_shader_state(GLcontext *ctx) +{ + /* Device drivers may override these to control what kind of instructions + * are generated by the GLSL compiler. + */ + ctx->Shader.EmitHighLevelInstructions = GL_TRUE; + ctx->Shader.EmitContReturn = GL_TRUE; + ctx->Shader.EmitCondCodes = GL_FALSE; + ctx->Shader.EmitComments = GL_FALSE; + ctx->Shader.Flags = get_shader_flags(); + + /* Default pragma settings */ + ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE; + ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE; + ctx->Shader.DefaultPragmas.Optimize = GL_TRUE; + ctx->Shader.DefaultPragmas.Debug = GL_FALSE; +} + + +/** + * Free the per-context shader-related state. + */ +void +_mesa_free_shader_state(GLcontext *ctx) +{ + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL); +} + + +/** + * Return the size of the given GLSL datatype, in floats (components). + */ +GLint +_mesa_sizeof_glsl_type(GLenum type) +{ + switch (type) { + case GL_FLOAT: + case GL_INT: + case GL_BOOL: + 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: + case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_CUBE_SHADOW_EXT: + return 1; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + case GL_BOOL_VEC2: + return 2; + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_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 _mesa_sizeof_glsl_type()"); + return 1; + } +} + + +/** + * Copy string from <src> to <dst>, up to maxLength characters, returning + * length of <dst> in <length>. + * \param src the strings source + * \param maxLength max chars to copy + * \param length returns number of chars copied + * \param dst the string destination + */ +void +_mesa_copy_string(GLchar *dst, GLsizei maxLength, + GLsizei *length, const GLchar *src) +{ + GLsizei len; + for (len = 0; len < maxLength - 1 && src && src[len]; len++) + dst[len] = src[len]; + if (maxLength > 0) + dst[len] = 0; + if (length) + *length = len; +} + + + +/** + * Find the length of the longest transform feedback varying name + * which was specified with glTransformFeedbackVaryings(). + */ +static GLint +longest_feedback_varying_name(const struct gl_shader_program *shProg) +{ + GLuint i; + GLint max = 0; + for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { + GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]); + if (len > max) + max = len; + } + return max; +} + + + +static GLboolean +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 +is_shader(GLcontext *ctx, GLuint name) +{ + struct gl_shader *shader = _mesa_lookup_shader(ctx, name); + return shader ? GL_TRUE : GL_FALSE; +} + + +/** + * Attach shader to a shader program. + */ +static void +attach_shader(GLcontext *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + struct gl_shader *sh; + GLuint i, n; + + 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) { + /* The shader is already attched to this program. The + * GL_ARB_shader_objects spec says: + * + * "The error INVALID_OPERATION is generated by AttachObjectARB + * if <obj> is already attached to <containerObj>." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); + return; + } + } + + /* grow list */ + shProg->Shaders = (struct gl_shader **) + _mesa_realloc(shProg->Shaders, + n * sizeof(struct gl_shader *), + (n + 1) * sizeof(struct gl_shader *)); + if (!shProg->Shaders) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); + return; + } + + /* append */ + shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ + _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); + shProg->NumShaders++; +} + + +static GLint +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->VertexProgram) { + const struct gl_program_parameter_list *attribs = + shProg->VertexProgram->Base.Attributes; + if (attribs) { + GLint i = _mesa_lookup_parameter_index(attribs, -1, name); + if (i >= 0) { + return attribs->Parameters[i].StateIndexes[0]; + } + } + } + return -1; +} + + +static void +bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, + const GLchar *name) +{ + 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) { + return; + } + + if (!name) + return; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindAttribLocation(illegal name)"); + 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 = get_attrib_location(ctx, program, name); + } + else { + oldIndex = -1; + } + + /* this will replace the current value if it's already in the list */ + i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index); + if (i < 0) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation"); + return; + } + + /* + * Note that this attribute binding won't go into effect until + * glLinkProgram is called again. + */ +} + + +static GLuint +create_shader(GLcontext *ctx, GLenum type) +{ + struct gl_shader *sh; + GLuint name; + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + + switch (type) { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + sh = ctx->Driver.NewShader(ctx, name, type); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); + return 0; + } + + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); + + return name; +} + + +static GLuint +create_shader_program(GLcontext *ctx) +{ + GLuint name; + struct gl_shader_program *shProg; + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + + shProg = ctx->Driver.NewShaderProgram(ctx, name); + + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); + + assert(shProg->RefCount == 1); + + return name; +} + + +/** + * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's + * DeleteProgramARB. + */ +static void +delete_shader_program(GLcontext *ctx, GLuint name) +{ + /* + * NOTE: deleting shaders/programs works a bit differently than + * texture objects (and buffer objects, etc). Shader/program + * handles/IDs exist in the hash table until the object is really + * deleted (refcount==0). With texture objects, the handle/ID is + * removed from the hash table in glDeleteTextures() while the tex + * object itself might linger until its refcount goes to zero. + */ + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram"); + if (!shProg) + return; + + shProg->DeletePending = GL_TRUE; + + /* effectively, decr shProg's refcount */ + _mesa_reference_shader_program(ctx, &shProg, NULL); +} + + +static void +delete_shader(GLcontext *ctx, GLuint shader) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader"); + if (!sh) + return; + + sh->DeletePending = GL_TRUE; + + /* effectively, decr sh's refcount */ + _mesa_reference_shader(ctx, &sh, NULL); +} + + +static void +detach_shader(GLcontext *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + GLuint n; + GLuint i, j; + + 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; + + /* release */ + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + + /* alloc new, smaller array */ + newList = (struct gl_shader **) + malloc((n - 1) * sizeof(struct gl_shader *)); + if (!newList) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader"); + return; + } + for (j = 0; j < i; j++) { + newList[j] = shProg->Shaders[j]; + } + while (++i < n) + newList[j++] = shProg->Shaders[i]; + free(shProg->Shaders); + + shProg->Shaders = newList; + shProg->NumShaders = n - 1; + +#ifdef DEBUG + /* sanity check */ + { + for (j = 0; j < shProg->NumShaders; j++) { + assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER || + shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER); + assert(shProg->Shaders[j]->RefCount > 0); + } + } +#endif + + return; + } + } + + /* not found */ + { + GLenum err; + if (is_shader(ctx, shader)) + err = GL_INVALID_OPERATION; + else if (is_program(ctx, shader)) + err = GL_INVALID_OPERATION; + else + err = GL_INVALID_VALUE; + _mesa_error(ctx, err, "glDetachProgram(shader)"); + return; + } +} + + +static void +get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, + GLsizei maxLength, GLsizei *length, GLint *size, + GLenum *type, GLchar *nameOut) +{ + const struct gl_program_parameter_list *attribs = NULL; + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); + if (!shProg) + return; + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + + if (!attribs || index >= attribs->NumParameters) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); + return; + } + + _mesa_copy_string(nameOut, maxLength, length, + attribs->Parameters[index].Name); + + if (size) + *size = attribs->Parameters[index].Size + / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType); + + if (type) + *type = attribs->Parameters[index].DataType; +} + + +/** + * Return list of shaders attached to shader program. + */ +static void +get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj) +{ + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders"); + if (shProg) { + GLuint i; + for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { + obj[i] = shProg->Shaders[i]->Name; + } + if (count) + *count = i; + } +} + + +/** + * glGetHandleARB() - return ID/name of currently bound shader program. + */ +static GLuint +get_handle(GLcontext *ctx, GLenum pname) +{ + if (pname == GL_PROGRAM_OBJECT_ARB) { + if (ctx->Shader.CurrentProgram) + return ctx->Shader.CurrentProgram->Name; + else + return 0; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB"); + return 0; + } +} + + +/** + * glGetProgramiv() - get shader program state. + * Note that this is for GLSL shader programs, not ARB vertex/fragment + * programs (see glGetProgramivARB). + */ +static void +get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params) +{ + const struct gl_program_parameter_list *attribs; + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)"); + return; + } + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + else + attribs = NULL; + + switch (pname) { + case GL_DELETE_STATUS: + *params = shProg->DeletePending; + break; + case GL_LINK_STATUS: + *params = shProg->LinkStatus; + break; + case GL_VALIDATE_STATUS: + *params = shProg->Validated; + break; + case GL_INFO_LOG_LENGTH: + *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0; + break; + case GL_ATTACHED_SHADERS: + *params = shProg->NumShaders; + break; + case GL_ACTIVE_ATTRIBUTES: + *params = attribs ? attribs->NumParameters : 0; + break; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1; + break; + case GL_ACTIVE_UNIFORMS: + *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; + break; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = _mesa_longest_uniform_name(shProg->Uniforms); + if (*params > 0) + (*params)++; /* add one for terminating zero */ + break; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = 0; + break; +#if FEATURE_EXT_transform_feedback + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = shProg->TransformFeedback.NumVarying; + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = longest_feedback_varying_name(shProg) + 1; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = shProg->TransformFeedback.BufferMode; + break; +#endif + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)"); + return; + } +} + + +/** + * glGetShaderiv() - get GLSL shader state + */ +static void +get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) +{ + struct gl_shader *shader = + _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); + + if (!shader) { + return; + } + + switch (pname) { + case GL_SHADER_TYPE: + *params = shader->Type; + break; + case GL_DELETE_STATUS: + *params = shader->DeletePending; + break; + case GL_COMPILE_STATUS: + *params = shader->CompileStatus; + break; + case GL_INFO_LOG_LENGTH: + *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; + break; + case GL_SHADER_SOURCE_LENGTH: + *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)"); + return; + } +} + + +static void +get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)"); + return; + } + _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog); +} + + +static void +get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)"); + return; + } + _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog); +} + + +/** + * Return shader source code. + */ +static void +get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength, + GLsizei *length, GLchar *sourceOut) +{ + struct gl_shader *sh; + sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource"); + if (!sh) { + return; + } + _mesa_copy_string(sourceOut, maxLength, length, sh->Source); +} + + +/** + * Set/replace shader source code. + */ +static void +shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) +{ + 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) { + free((void *) sh->Source); + } + sh->Source = source; + sh->CompileStatus = GL_FALSE; +#ifdef DEBUG + sh->SourceChecksum = _mesa_str_checksum(sh->Source); +#endif +} + + +/** + * Compile a shader. + */ +static void +compile_shader(GLcontext *ctx, GLuint shaderObj) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); + if (!sh) + return; + + /* set default pragma state for shader */ + sh->Pragmas = ctx->Shader.DefaultPragmas; + + /* this call will set the sh->CompileStatus field to indicate if + * compilation was successful. + */ + (void) _slang_compile(ctx, sh); +} + + +/** + * Link a program's shaders. + */ +static void +link_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + struct gl_transform_feedback_object *obj = + ctx->TransformFeedback.CurrentObject; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); + if (!shProg) + return; + + if (obj->Active && shProg == ctx->Shader.CurrentProgram) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLinkProgram(transform feedback active"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + _slang_link(ctx, program, shProg); + + /* debug code */ + if (0) { + GLuint i; + + printf("Link %u shaders in program %u: %s\n", + shProg->NumShaders, shProg->Name, + shProg->LinkStatus ? "Success" : "Failed"); + + for (i = 0; i < shProg->NumShaders; i++) { + printf(" shader %u, type 0x%x\n", + shProg->Shaders[i]->Name, + shProg->Shaders[i]->Type); + } + } +} + + +/** + * Print basic shader info (for debug). + */ +static void +print_shader_info(const struct gl_shader_program *shProg) +{ + GLuint i; + + printf("Mesa: glUseProgram(%u)\n", shProg->Name); + for (i = 0; i < shProg->NumShaders; i++) { + const char *s; + switch (shProg->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + s = "vertex"; + break; + case GL_FRAGMENT_SHADER: + s = "fragment"; + break; + case GL_GEOMETRY_SHADER: + s = "geometry"; + break; + default: + s = ""; + } + printf(" %s shader %u, checksum %u\n", s, + shProg->Shaders[i]->Name, + shProg->Shaders[i]->SourceChecksum); + } + if (shProg->VertexProgram) + printf(" vert prog %u\n", shProg->VertexProgram->Base.Id); + if (shProg->FragmentProgram) + printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id); +} + + +/** + * Use the named shader program for subsequent rendering. + */ +void +_mesa_use_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + struct gl_transform_feedback_object *obj = + ctx->TransformFeedback.CurrentObject; + + if (obj->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(transform feedback active)"); + return; + } + + if (ctx->Shader.CurrentProgram && + ctx->Shader.CurrentProgram->Name == program) { + /* no-op */ + return; + } + + if (program) { + shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); + if (!shProg) { + return; + } + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(program %u not linked)", program); + return; + } + + /* debug code */ + if (ctx->Shader.Flags & GLSL_USE_PROG) { + print_shader_info(shProg); + } + } + else { + shProg = NULL; + } + + if (ctx->Shader.CurrentProgram != shProg) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg); + } + + if (ctx->Driver.UseProgram) + ctx->Driver.UseProgram(ctx, shProg); +} + + +/** + * Validate a program's samplers. + * Specifically, check that there aren't two samplers of different types + * pointing to the same texture unit. + * \return GL_TRUE if valid, GL_FALSE if invalid + */ +static GLboolean +validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg) +{ + static const char *targetName[] = { + "TEXTURE_2D_ARRAY", + "TEXTURE_1D_ARRAY", + "TEXTURE_CUBE", + "TEXTURE_3D", + "TEXTURE_RECT", + "TEXTURE_2D", + "TEXTURE_1D", + }; + GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS]; + GLbitfield samplersUsed = prog->SamplersUsed; + GLuint i; + + assert(Elements(targetName) == NUM_TEXTURE_TARGETS); + + if (samplersUsed == 0x0) + return GL_TRUE; + + for (i = 0; i < Elements(targetUsed); i++) + targetUsed[i] = -1; + + /* walk over bits which are set in 'samplers' */ + while (samplersUsed) { + GLuint unit; + gl_texture_index target; + GLint sampler = _mesa_ffs(samplersUsed) - 1; + assert(sampler >= 0); + assert(sampler < MAX_TEXTURE_IMAGE_UNITS); + unit = prog->SamplerUnits[sampler]; + target = prog->SamplerTargets[sampler]; + if (targetUsed[unit] != -1 && targetUsed[unit] != target) { + _mesa_snprintf(errMsg, 100, + "Texture unit %d is accessed both as %s and %s", + unit, targetName[targetUsed[unit]], targetName[target]); + return GL_FALSE; + } + targetUsed[unit] = target; + samplersUsed ^= (1 << sampler); + } + + return GL_TRUE; +} + + +/** + * Do validation of the given shader program. + * \param errMsg returns error message if validation fails. + * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg) + */ +static GLboolean +validate_shader_program(GLcontext *ctx, + const struct gl_shader_program *shProg, + char *errMsg) +{ + const struct gl_vertex_program *vp = shProg->VertexProgram; + const struct gl_fragment_program *fp = shProg->FragmentProgram; + + if (!shProg->LinkStatus) { + return GL_FALSE; + } + + /* 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, + + any active sampler in the current program object refers to a texture + image unit where fixed-function fragment processing accesses a + texture target that does not match the sampler type, or + + the sum of the number of active samplers in the program and the + number of texture image units enabled for fixed-function fragment + processing exceeds the combined limit on the total number of texture + image units allowed. + */ + + + /* + * Check: any two active samplers in the current program object are of + * different types, but refer to the same texture image unit, + */ + if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) { + return GL_FALSE; + } + if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) { + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Called via glValidateProgram() + */ +static void +validate_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + char errMsg[100]; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram"); + if (!shProg) { + return; + } + + shProg->Validated = validate_shader_program(ctx, shProg, errMsg); + if (!shProg->Validated) { + /* update info log */ + if (shProg->InfoLog) { + free(shProg->InfoLog); + } + shProg->InfoLog = _mesa_strdup(errMsg); + } +} + + + +void GLAPIENTRY +_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_AttachShader(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, + const GLcharARB *name) +{ + GET_CURRENT_CONTEXT(ctx); + bind_attrib_location(ctx, program, index, name); +} + + +void GLAPIENTRY +_mesa_CompileShaderARB(GLhandleARB shaderObj) +{ + GET_CURRENT_CONTEXT(ctx); + compile_shader(ctx, shaderObj); +} + + +GLuint GLAPIENTRY +_mesa_CreateShader(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader(ctx, type); +} + + +GLhandleARB GLAPIENTRY +_mesa_CreateShaderObjectARB(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader(ctx, type); +} + + +GLuint GLAPIENTRY +_mesa_CreateProgram(void) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader_program(ctx); +} + + +GLhandleARB GLAPIENTRY +_mesa_CreateProgramObjectARB(void) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader_program(ctx); +} + + +void GLAPIENTRY +_mesa_DeleteObjectARB(GLhandleARB obj) +{ + if (obj) { + GET_CURRENT_CONTEXT(ctx); + if (is_program(ctx, obj)) { + delete_shader_program(ctx, obj); + } + else if (is_shader(ctx, obj)) { + delete_shader(ctx, obj); + } + else { + /* error? */ + } + } +} + + +void GLAPIENTRY +_mesa_DeleteProgram(GLuint name) +{ + if (name) { + GET_CURRENT_CONTEXT(ctx); + delete_shader_program(ctx, name); + } +} + + +void GLAPIENTRY +_mesa_DeleteShader(GLuint name) +{ + if (name) { + GET_CURRENT_CONTEXT(ctx); + delete_shader(ctx, name); + } +} + + +void GLAPIENTRY +_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_DetachShader(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index, + GLsizei maxLength, GLsizei * length, GLint * size, + GLenum * type, GLcharARB * name) +{ + GET_CURRENT_CONTEXT(ctx); + get_active_attrib(ctx, program, index, maxLength, length, size, type, name); +} + + +void GLAPIENTRY +_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount, + GLsizei * count, GLhandleARB * obj) +{ + GET_CURRENT_CONTEXT(ctx); + get_attached_shaders(ctx, container, maxCount, count, obj); +} + + +void GLAPIENTRY +_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj) +{ + GET_CURRENT_CONTEXT(ctx); + get_attached_shaders(ctx, program, maxCount, count, obj); +} + + +GLint GLAPIENTRY +_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) +{ + GET_CURRENT_CONTEXT(ctx); + return get_attrib_location(ctx, program, name); +} + + +void GLAPIENTRY +_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length, + GLcharARB * infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + if (is_program(ctx, object)) { + get_program_info_log(ctx, object, maxLength, length, infoLog); + } + else if (is_shader(ctx, object)) { + get_shader_info_log(ctx, object, maxLength, length, infoLog); + } + else { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB"); + } +} + + +void GLAPIENTRY +_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + /* Implement in terms of GetProgramiv, GetShaderiv */ + if (is_program(ctx, object)) { + if (pname == GL_OBJECT_TYPE_ARB) { + *params = GL_PROGRAM_OBJECT_ARB; + } + else { + get_programiv(ctx, object, pname, params); + } + } + else if (is_shader(ctx, object)) { + if (pname == GL_OBJECT_TYPE_ARB) { + *params = GL_SHADER_OBJECT_ARB; + } + else { + get_shaderiv(ctx, object, pname, params); + } + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB"); + } +} + + +void GLAPIENTRY +_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname, + GLfloat *params) +{ + GLint iparams[1]; /* XXX is one element enough? */ + _mesa_GetObjectParameterivARB(object, pname, iparams); + params[0] = (GLfloat) iparams[0]; +} + + +void GLAPIENTRY +_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + get_programiv(ctx, program, pname, params); +} + + +void GLAPIENTRY +_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + get_shaderiv(ctx, shader, pname, params); +} + + +void GLAPIENTRY +_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + get_program_info_log(ctx, program, bufSize, length, infoLog); +} + + +void GLAPIENTRY +_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + get_shader_info_log(ctx, shader, bufSize, length, infoLog); +} + + +void GLAPIENTRY +_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength, + GLsizei *length, GLcharARB *sourceOut) +{ + GET_CURRENT_CONTEXT(ctx); + get_shader_source(ctx, shader, maxLength, length, sourceOut); +} + + +GLhandleARB GLAPIENTRY +_mesa_GetHandleARB(GLenum pname) +{ + GET_CURRENT_CONTEXT(ctx); + return get_handle(ctx, pname); +} + + +GLboolean GLAPIENTRY +_mesa_IsProgram(GLuint name) +{ + GET_CURRENT_CONTEXT(ctx); + return is_program(ctx, name); +} + + +GLboolean GLAPIENTRY +_mesa_IsShader(GLuint name) +{ + GET_CURRENT_CONTEXT(ctx); + return is_shader(ctx, name); +} + + +void GLAPIENTRY +_mesa_LinkProgramARB(GLhandleARB programObj) +{ + GET_CURRENT_CONTEXT(ctx); + link_program(ctx, programObj); +} + + + +/** + * Read shader source code from a file. + * Useful for debugging to override an app's shader. + */ +static GLcharARB * +read_shader(const char *fname) +{ + const int max = 50*1000; + FILE *f = fopen(fname, "r"); + GLcharARB *buffer, *shader; + int len; + + if (!f) { + return NULL; + } + + buffer = (char *) malloc(max); + len = fread(buffer, 1, max, f); + buffer[len] = 0; + + fclose(f); + + shader = _mesa_strdup(buffer); + free(buffer); + + return shader; +} + + +/** + * Called via glShaderSource() and glShaderSourceARB() API functions. + * Basically, concatenate the source code strings into one long string + * and pass it to _mesa_shader_source(). + */ +void GLAPIENTRY +_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, + const GLcharARB ** string, const GLint * length) +{ + GET_CURRENT_CONTEXT(ctx); + GLint *offsets; + GLsizei i, totalLength; + GLcharARB *source; + GLuint checksum; + + if (!shaderObj || string == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); + return; + } + + /* + * This array holds offsets of where the appropriate string ends, thus the + * last element will be set to the total length of the source code. + */ + offsets = (GLint *) malloc(count * sizeof(GLint)); + if (offsets == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); + return; + } + + for (i = 0; i < count; i++) { + if (string[i] == NULL) { + free((GLvoid *) offsets); + _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); + return; + } + if (length == NULL || length[i] < 0) + offsets[i] = strlen(string[i]); + else + offsets[i] = length[i]; + /* accumulate string lengths */ + if (i > 0) + offsets[i] += offsets[i - 1]; + } + + /* Total length of source string is sum off all strings plus two. + * One extra byte for terminating zero, another extra byte to silence + * valgrind warnings in the parser/grammer code. + */ + totalLength = offsets[count - 1] + 2; + source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB)); + if (source == NULL) { + free((GLvoid *) offsets); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); + return; + } + + for (i = 0; i < count; i++) { + GLint start = (i > 0) ? offsets[i - 1] : 0; + memcpy(source + start, string[i], + (offsets[i] - start) * sizeof(GLcharARB)); + } + source[totalLength - 1] = '\0'; + source[totalLength - 2] = '\0'; + + if (SHADER_SUBST) { + /* Compute the shader's source code checksum then try to open a file + * named newshader_<CHECKSUM>. If it exists, use it in place of the + * original shader source code. For debugging. + */ + char filename[100]; + GLcharARB *newSource; + + checksum = _mesa_str_checksum(source); + + _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); + + newSource = read_shader(filename); + if (newSource) { + fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", + shaderObj, checksum, filename); + free(source); + source = newSource; + } + } + + shader_source(ctx, shaderObj, source); + + if (SHADER_SUBST) { + struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); + if (sh) + sh->SourceChecksum = checksum; /* save original checksum */ + } + + free(offsets); +} + + +void GLAPIENTRY +_mesa_UseProgramObjectARB(GLhandleARB program) +{ + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_use_program(ctx, program); +} + + +void GLAPIENTRY +_mesa_ValidateProgramARB(GLhandleARB program) +{ + GET_CURRENT_CONTEXT(ctx); + validate_program(ctx, program); +} + +#ifdef FEATURE_ES2 + +void GLAPIENTRY +_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); +} + + +void GLAPIENTRY +_mesa_ReleaseShaderCompiler(void) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); +} + + +void GLAPIENTRY +_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, + const void* binary, GLint length) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); +} + +#endif /* FEATURE_ES2 */ + + +/** + * Plug in shader-related functions into API dispatch table. + */ +void +_mesa_init_shader_dispatch(struct _glapi_table *exec) +{ + /* GL_ARB_vertex/fragment_shader */ + SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB); + SET_GetHandleARB(exec, _mesa_GetHandleARB); + SET_DetachObjectARB(exec, _mesa_DetachObjectARB); + SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB); + SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB); + SET_CompileShaderARB(exec, _mesa_CompileShaderARB); + SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB); + SET_AttachObjectARB(exec, _mesa_AttachObjectARB); + SET_LinkProgramARB(exec, _mesa_LinkProgramARB); + SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB); + SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB); + SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB); + SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB); + SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB); + SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB); + SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB); + + /* OpenGL 2.0 */ + SET_AttachShader(exec, _mesa_AttachShader); + SET_CreateProgram(exec, _mesa_CreateProgram); + SET_CreateShader(exec, _mesa_CreateShader); + SET_DeleteProgram(exec, _mesa_DeleteProgram); + SET_DeleteShader(exec, _mesa_DeleteShader); + SET_DetachShader(exec, _mesa_DetachShader); + SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders); + SET_GetProgramiv(exec, _mesa_GetProgramiv); + SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog); + SET_GetShaderiv(exec, _mesa_GetShaderiv); + SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog); + SET_IsProgram(exec, _mesa_IsProgram); + SET_IsShader(exec, _mesa_IsShader); + +#if FEATURE_ARB_vertex_shader + SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB); + SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB); + SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB); +#endif +} + diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h new file mode 100644 index 00000000000..ec0c09a0e38 --- /dev/null +++ b/src/mesa/main/shaderapi.h @@ -0,0 +1,166 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SHADERAPI_H +#define SHADERAPI_H + + +#include "glheader.h" +#include "mtypes.h" + + +extern GLint +_mesa_sizeof_glsl_type(GLenum type); + +extern void +_mesa_copy_string(GLchar *dst, GLsizei maxLength, + GLsizei *length, const GLchar *src); + +extern void +_mesa_use_program(GLcontext *ctx, GLuint program); + + +extern void +_mesa_init_shader_dispatch(struct _glapi_table *exec); + + + +extern void GLAPIENTRY +_mesa_AttachObjectARB(GLhandleARB, GLhandleARB); + +extern void GLAPIENTRY +_mesa_CompileShaderARB(GLhandleARB); + +extern GLhandleARB GLAPIENTRY +_mesa_CreateProgramObjectARB(void); + +extern GLhandleARB GLAPIENTRY +_mesa_CreateShaderObjectARB(GLenum type); + +extern void GLAPIENTRY +_mesa_DeleteObjectARB(GLhandleARB obj); + +extern void GLAPIENTRY +_mesa_DetachObjectARB(GLhandleARB, GLhandleARB); + +extern void GLAPIENTRY +_mesa_GetAttachedObjectsARB(GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); + +extern GLhandleARB GLAPIENTRY +_mesa_GetHandleARB(GLenum pname); + +extern void GLAPIENTRY +_mesa_GetInfoLogARB(GLhandleARB, GLsizei, GLsizei *, GLcharARB *); + +extern void GLAPIENTRY +_mesa_GetObjectParameterfvARB(GLhandleARB, GLenum, GLfloat *); + +extern void GLAPIENTRY +_mesa_GetObjectParameterivARB(GLhandleARB, GLenum, GLint *); + +extern void GLAPIENTRY +_mesa_GetShaderSourceARB(GLhandleARB, GLsizei, GLsizei *, GLcharARB *); + +extern GLboolean GLAPIENTRY +_mesa_IsProgram(GLuint name); + +extern GLboolean GLAPIENTRY +_mesa_IsShader(GLuint name); + +extern void GLAPIENTRY +_mesa_LinkProgramARB(GLhandleARB programObj); + +extern void GLAPIENTRY +_mesa_ShaderSourceARB(GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); + +extern void GLAPIENTRY +_mesa_UseProgramObjectARB(GLhandleARB); + +extern void GLAPIENTRY +_mesa_ValidateProgramARB(GLhandleARB); + + +extern void GLAPIENTRY +_mesa_BindAttribLocationARB(GLhandleARB, GLuint, const GLcharARB *); + +extern void GLAPIENTRY +_mesa_GetActiveAttribARB(GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, + GLenum *, GLcharARB *); + +extern GLint GLAPIENTRY +_mesa_GetAttribLocationARB(GLhandleARB, const GLcharARB *); + + + +extern void GLAPIENTRY +_mesa_AttachShader(GLuint program, GLuint shader); + +extern GLuint GLAPIENTRY +_mesa_CreateShader(GLenum); + +extern GLuint GLAPIENTRY +_mesa_CreateProgram(void); + +extern void GLAPIENTRY +_mesa_DeleteProgram(GLuint program); + +extern void GLAPIENTRY +_mesa_DeleteShader(GLuint shader); + +extern void GLAPIENTRY +_mesa_DetachShader(GLuint program, GLuint shader); + +extern void GLAPIENTRY +_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj); + +extern void GLAPIENTRY +_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog); + +extern void GLAPIENTRY +_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog); + + +extern void GLAPIENTRY +_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint *range, GLint *precision); + +extern void GLAPIENTRY +_mesa_ReleaseShaderCompiler(void); + +extern void GLAPIENTRY +_mesa_ShaderBinary(GLint n, const GLuint *shaders, GLenum binaryformat, + const void* binary, GLint length); + + +#endif /* SHADERAPI_H */ diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c new file mode 100644 index 00000000000..d4d2349d4b6 --- /dev/null +++ b/src/mesa/main/shaderobj.c @@ -0,0 +1,386 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file shaderobj.c + * \author Brian Paul + * + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/dispatch.h" +#include "main/hash.h" +#include "main/shaderobj.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" + + +/**********************************************************************/ +/*** Shader object functions ***/ +/**********************************************************************/ + + +/** + * Set ptr to point to sh. + * If ptr is pointing to another shader, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to sh, incrementing its refcount. + */ +void +_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr, + struct gl_shader *sh) +{ + assert(ptr); + if (*ptr == sh) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader *old = *ptr; + + ASSERT(old->RefCount > 0); + old->RefCount--; + /*printf("SHADER DECR %p (%d) to %d\n", + (void*) old, old->Name, old->RefCount);*/ + deleteFlag = (old->RefCount == 0); + + if (deleteFlag) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + ctx->Driver.DeleteShader(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (sh) { + /* reference new */ + sh->RefCount++; + /*printf("SHADER INCR %p (%d) to %d\n", + (void*) sh, sh->Name, sh->RefCount);*/ + *ptr = sh; + } +} + + +/** + * Allocate a new gl_shader object, initialize it. + * Called via ctx->Driver.NewShader() + */ +static struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) +{ + struct gl_shader *shader; + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); + shader = CALLOC_STRUCT(gl_shader); + if (shader) { + shader->Type = type; + shader->Name = name; + shader->RefCount = 1; + } + return shader; +} + + +/** + * Delete a shader object. + * Called via ctx->Driver.DeleteShader(). + */ +static void +__mesa_delete_shader(GLcontext *ctx, struct gl_shader *sh) +{ + if (sh->Source) + free((void *) sh->Source); + if (sh->InfoLog) + free(sh->InfoLog); + _mesa_reference_program(ctx, &sh->Program, NULL); + free(sh); +} + + +/** + * Lookup a GLSL shader object. + */ +struct gl_shader * +_mesa_lookup_shader(GLcontext *ctx, GLuint name) +{ + if (name) { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return sh; + } + return NULL; +} + + +/** + * As above, but record an error if shader is not found. + */ +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; + } +} + + + +/**********************************************************************/ +/*** Shader Program object functions ***/ +/**********************************************************************/ + + +/** + * Set ptr to point to shProg. + * If ptr is pointing to another object, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to shProg, incrementing its refcount. + */ +void +_mesa_reference_shader_program(GLcontext *ctx, + struct gl_shader_program **ptr, + struct gl_shader_program *shProg) +{ + assert(ptr); + if (*ptr == shProg) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader program */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader_program *old = *ptr; + + ASSERT(old->RefCount > 0); + 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) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + ctx->Driver.DeleteShaderProgram(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (shProg) { + shProg->RefCount++; +#if 0 + printf("ShaderProgram %p ID=%u RefCount++ to %d\n", + (void *) shProg, shProg->Name, shProg->RefCount); +#endif + *ptr = shProg; + } +} + + +/** + * Allocate a new gl_shader_program object, initialize it. + * Called via ctx->Driver.NewShaderProgram() + */ +static struct gl_shader_program * +_mesa_new_shader_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + shProg = CALLOC_STRUCT(gl_shader_program); + if (shProg) { + shProg->Type = GL_SHADER_PROGRAM_MESA; + shProg->Name = name; + shProg->RefCount = 1; + shProg->Attributes = _mesa_new_parameter_list(); + } + return shProg; +} + + +/** + * Clear (free) the shader program state that gets produced by linking. + */ +void +_mesa_clear_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg) +{ + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); + + if (shProg->Uniforms) { + _mesa_free_uniform_list(shProg->Uniforms); + shProg->Uniforms = NULL; + } + + if (shProg->Varying) { + _mesa_free_parameter_list(shProg->Varying); + shProg->Varying = NULL; + } +} + + +/** + * Free all the data that hangs off a shader program object, but not the + * object itself. + */ +void +_mesa_free_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg) +{ + GLuint i; + + assert(shProg->Type == GL_SHADER_PROGRAM_MESA); + + _mesa_clear_shader_program_data(ctx, shProg); + + if (shProg->Attributes) { + _mesa_free_parameter_list(shProg->Attributes); + shProg->Attributes = NULL; + } + + /* detach shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + } + shProg->NumShaders = 0; + + if (shProg->Shaders) { + free(shProg->Shaders); + shProg->Shaders = NULL; + } + + if (shProg->InfoLog) { + free(shProg->InfoLog); + shProg->InfoLog = NULL; + } + + /* Transform feedback varying vars */ + for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { + free(shProg->TransformFeedback.VaryingNames[i]); + } + free(shProg->TransformFeedback.VaryingNames); + shProg->TransformFeedback.VaryingNames = NULL; + shProg->TransformFeedback.NumVarying = 0; +} + + +/** + * Free/delete a shader program object. + * Called via ctx->Driver.DeleteShaderProgram(). + */ +static void +__mesa_delete_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) +{ + _mesa_free_shader_program_data(ctx, shProg); + + free(shProg); +} + + +/** + * Lookup a GLSL program object. + */ +struct gl_shader_program * +_mesa_lookup_shader_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + if (name) { + shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return shProg; + } + return NULL; +} + + +/** + * As above, but record an error if program is not found. + */ +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; + } +} + + +void +_mesa_init_shader_object_functions(struct dd_function_table *driver) +{ + driver->NewShader = _mesa_new_shader; + driver->DeleteShader = __mesa_delete_shader; + driver->NewShaderProgram = _mesa_new_shader_program; + driver->DeleteShaderProgram = __mesa_delete_shader_program; +} diff --git a/src/mesa/main/shaderobj.h b/src/mesa/main/shaderobj.h new file mode 100644 index 00000000000..d6b37b45963 --- /dev/null +++ b/src/mesa/main/shaderobj.h @@ -0,0 +1,78 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2004-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef SHADEROBJ_H +#define SHADEROBJ_H + + +#include "glheader.h" +#include "mtypes.h" + + +extern void +_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr, + struct gl_shader *sh); + +extern struct gl_shader * +_mesa_lookup_shader(GLcontext *ctx, GLuint name); + +extern struct gl_shader * +_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller); + + + +extern void +_mesa_reference_shader_program(GLcontext *ctx, + struct gl_shader_program **ptr, + struct gl_shader_program *shProg); + +extern struct gl_shader_program * +_mesa_lookup_shader_program(GLcontext *ctx, GLuint name); + +extern struct gl_shader_program * +_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name, + const char *caller); + +extern void +_mesa_clear_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg); + +extern void +_mesa_free_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg); + + + +extern void +_mesa_init_shader_object_functions(struct dd_function_table *driver); + +extern void +_mesa_init_shader_state(GLcontext *ctx); + +extern void +_mesa_free_shader_state(GLcontext *ctx); + + +#endif /* SHADEROBJ_H */ diff --git a/src/mesa/main/shaders.c b/src/mesa/main/shaders.c deleted file mode 100644 index 65f1ee3efbd..00000000000 --- a/src/mesa/main/shaders.c +++ /dev/null @@ -1,932 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "context.h" -#include "shaders.h" -#include "shader/shader_api.h" -#include "main/dispatch.h" - - -/** Define this to enable shader substitution (see below) */ -#define SHADER_SUBST 0 - - - -/** - * These are basically just wrappers/adaptors for calling the - * ctx->Driver.foobar() GLSL-related functions. - * - * Things are biased toward the OpenGL 2.0 functions rather than the - * ARB extensions (i.e. the ARB functions are layered on the 2.0 functions). - * - * The general idea here is to allow enough modularity such that a - * completely different GLSL implemenation can be plugged in and co-exist - * with Mesa's native GLSL code. - */ - - - -void GLAPIENTRY -_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.AttachShader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_AttachShader(GLuint program, GLuint shader) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.AttachShader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, - const GLcharARB *name) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.BindAttribLocation(ctx, program, index, name); -} - - -void GLAPIENTRY -_mesa_CompileShaderARB(GLhandleARB shaderObj) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.CompileShader(ctx, shaderObj); -} - - -GLuint GLAPIENTRY -_mesa_CreateShader(GLenum type) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.CreateShader(ctx, type); -} - - -GLhandleARB GLAPIENTRY -_mesa_CreateShaderObjectARB(GLenum type) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.CreateShader(ctx, type); -} - - -GLuint GLAPIENTRY -_mesa_CreateProgram(void) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.CreateProgram(ctx); -} - - -GLhandleARB GLAPIENTRY -_mesa_CreateProgramObjectARB(void) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.CreateProgram(ctx); -} - - -void GLAPIENTRY -_mesa_DeleteObjectARB(GLhandleARB obj) -{ - if (obj) { - GET_CURRENT_CONTEXT(ctx); - if (ctx->Driver.IsProgram(ctx, obj)) { - ctx->Driver.DeleteProgram2(ctx, obj); - } - else if (ctx->Driver.IsShader(ctx, obj)) { - ctx->Driver.DeleteShader(ctx, obj); - } - else { - /* error? */ - } - } -} - - -void GLAPIENTRY -_mesa_DeleteProgram(GLuint name) -{ - if (name) { - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.DeleteProgram2(ctx, name); - } -} - - -void GLAPIENTRY -_mesa_DeleteShader(GLuint name) -{ - if (name) { - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.DeleteShader(ctx, name); - } -} - - -void GLAPIENTRY -_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.DetachShader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_DetachShader(GLuint program, GLuint shader) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.DetachShader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index, - GLsizei maxLength, GLsizei * length, GLint * size, - GLenum * type, GLcharARB * name) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetActiveAttrib(ctx, program, index, maxLength, length, size, - type, name); -} - - -void GLAPIENTRY -_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index, - GLsizei maxLength, GLsizei * length, GLint * size, - GLenum * type, GLcharARB * name) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetActiveUniform(ctx, program, index, maxLength, length, size, - type, name); -} - - -void GLAPIENTRY -_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount, - GLsizei * count, GLhandleARB * obj) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetAttachedShaders(ctx, container, maxCount, count, obj); -} - - -void GLAPIENTRY -_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetAttachedShaders(ctx, program, maxCount, count, obj); -} - - -GLint GLAPIENTRY -_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.GetAttribLocation(ctx, program, name); -} - - -void GLAPIENTRY -_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length, - GLcharARB * infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - /* Implement in terms of GetProgramInfoLog, GetShaderInfoLog */ - if (ctx->Driver.IsProgram(ctx, object)) { - ctx->Driver.GetProgramInfoLog(ctx, object, maxLength, length, infoLog); - } - else if (ctx->Driver.IsShader(ctx, object)) { - ctx->Driver.GetShaderInfoLog(ctx, object, maxLength, length, infoLog); - } - else { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB"); - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - /* Implement in terms of GetProgramiv, GetShaderiv */ - if (ctx->Driver.IsProgram(ctx, object)) { - if (pname == GL_OBJECT_TYPE_ARB) { - *params = GL_PROGRAM_OBJECT_ARB; - } - else { - ctx->Driver.GetProgramiv(ctx, object, pname, params); - } - } - else if (ctx->Driver.IsShader(ctx, object)) { - if (pname == GL_OBJECT_TYPE_ARB) { - *params = GL_SHADER_OBJECT_ARB; - } - else { - ctx->Driver.GetShaderiv(ctx, object, pname, params); - } - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB"); - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname, - GLfloat *params) -{ - GLint iparams[1]; /* XXX is one element enough? */ - _mesa_GetObjectParameterivARB(object, pname, iparams); - params[0] = (GLfloat) iparams[0]; -} - - -void GLAPIENTRY -_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetProgramiv(ctx, program, pname, params); -} - - -void GLAPIENTRY -_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetShaderiv(ctx, shader, pname, params); -} - - -void GLAPIENTRY -_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetProgramInfoLog(ctx, program, bufSize, length, infoLog); -} - - -void GLAPIENTRY -_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetShaderInfoLog(ctx, shader, bufSize, length, infoLog); -} - - -void GLAPIENTRY -_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength, - GLsizei *length, GLcharARB *sourceOut) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetShaderSource(ctx, shader, maxLength, length, sourceOut); -} - - -void GLAPIENTRY -_mesa_GetUniformfvARB(GLhandleARB program, GLint location, GLfloat * params) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetUniformfv(ctx, program, location, params); -} - - -void GLAPIENTRY -_mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint * params) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.GetUniformiv(ctx, program, location, params); -} - - - -#if 0 -GLint GLAPIENTRY -_mesa_GetUniformLocation(GLuint program, const GLcharARB *name) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.GetUniformLocation(ctx, program, name); -} -#endif - - -GLhandleARB GLAPIENTRY -_mesa_GetHandleARB(GLenum pname) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.GetHandle(ctx, pname); -} - - -GLint GLAPIENTRY -_mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.GetUniformLocation(ctx, programObj, name); -} - - -GLboolean GLAPIENTRY -_mesa_IsProgram(GLuint name) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.IsProgram(ctx, name); -} - - -GLboolean GLAPIENTRY -_mesa_IsShader(GLuint name) -{ - GET_CURRENT_CONTEXT(ctx); - return ctx->Driver.IsShader(ctx, name); -} - - -void GLAPIENTRY -_mesa_LinkProgramARB(GLhandleARB programObj) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.LinkProgram(ctx, programObj); -} - - - -/** - * Read shader source code from a file. - * Useful for debugging to override an app's shader. - */ -static GLcharARB * -_mesa_read_shader(const char *fname) -{ - const int max = 50*1000; - FILE *f = fopen(fname, "r"); - GLcharARB *buffer, *shader; - int len; - - if (!f) { - return NULL; - } - - buffer = (char *) malloc(max); - len = fread(buffer, 1, max, f); - buffer[len] = 0; - - fclose(f); - - shader = _mesa_strdup(buffer); - free(buffer); - - return shader; -} - - -/** - * Called via glShaderSource() and glShaderSourceARB() API functions. - * Basically, concatenate the source code strings into one long string - * and pass it to ctx->Driver.ShaderSource(). - */ -void GLAPIENTRY -_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, - const GLcharARB ** string, const GLint * length) -{ - GET_CURRENT_CONTEXT(ctx); - GLint *offsets; - GLsizei i, totalLength; - GLcharARB *source; - GLuint checksum; - - if (!shaderObj || string == NULL) { - _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); - return; - } - - /* - * This array holds offsets of where the appropriate string ends, thus the - * last element will be set to the total length of the source code. - */ - offsets = (GLint *) malloc(count * sizeof(GLint)); - if (offsets == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); - return; - } - - for (i = 0; i < count; i++) { - if (string[i] == NULL) { - free((GLvoid *) offsets); - _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); - return; - } - if (length == NULL || length[i] < 0) - offsets[i] = strlen(string[i]); - else - offsets[i] = length[i]; - /* accumulate string lengths */ - if (i > 0) - offsets[i] += offsets[i - 1]; - } - - /* Total length of source string is sum off all strings plus two. - * One extra byte for terminating zero, another extra byte to silence - * valgrind warnings in the parser/grammer code. - */ - totalLength = offsets[count - 1] + 2; - source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB)); - if (source == NULL) { - free((GLvoid *) offsets); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); - return; - } - - for (i = 0; i < count; i++) { - GLint start = (i > 0) ? offsets[i - 1] : 0; - memcpy(source + start, string[i], - (offsets[i] - start) * sizeof(GLcharARB)); - } - source[totalLength - 1] = '\0'; - source[totalLength - 2] = '\0'; - - if (SHADER_SUBST) { - /* Compute the shader's source code checksum then try to open a file - * named newshader_<CHECKSUM>. If it exists, use it in place of the - * original shader source code. For debugging. - */ - char filename[100]; - GLcharARB *newSource; - - checksum = _mesa_str_checksum(source); - - _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); - - newSource = _mesa_read_shader(filename); - if (newSource) { - fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", - shaderObj, checksum, filename); - free(source); - source = newSource; - } - } - - ctx->Driver.ShaderSource(ctx, shaderObj, source); - - if (SHADER_SUBST) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); - if (sh) - sh->SourceChecksum = checksum; /* save original checksum */ - } - - free(offsets); -} - - -void GLAPIENTRY -_mesa_Uniform1fARB(GLint location, GLfloat v0) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, 1, &v0, GL_FLOAT); -} - -void GLAPIENTRY -_mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1) -{ - GET_CURRENT_CONTEXT(ctx); - GLfloat v[2]; - v[0] = v0; - v[1] = v1; - ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) -{ - GET_CURRENT_CONTEXT(ctx); - GLfloat v[3]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, - GLfloat v3) -{ - GET_CURRENT_CONTEXT(ctx); - GLfloat v[4]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - v[3] = v3; - ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC4); -} - -void GLAPIENTRY -_mesa_Uniform1iARB(GLint location, GLint v0) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, 1, &v0, GL_INT); -} - -void GLAPIENTRY -_mesa_Uniform2iARB(GLint location, GLint v0, GLint v1) -{ - GET_CURRENT_CONTEXT(ctx); - GLint v[2]; - v[0] = v0; - v[1] = v1; - ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2) -{ - GET_CURRENT_CONTEXT(ctx); - GLint v[3]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) -{ - GET_CURRENT_CONTEXT(ctx); - GLint v[4]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - v[3] = v3; - ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC4); -} - -void GLAPIENTRY -_mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT); -} - -void GLAPIENTRY -_mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC4); -} - -void GLAPIENTRY -_mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_INT); -} - -void GLAPIENTRY -_mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC4); -} - - -/** OpenGL 3.0 GLuint-valued functions **/ -void GLAPIENTRY -_mesa_Uniform1ui(GLint location, GLuint v0) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, 1, &v0, GL_UNSIGNED_INT); -} - -void GLAPIENTRY -_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint v[2]; - v[0] = v0; - v[1] = v1; - ctx->Driver.Uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint v[3]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - ctx->Driver.Uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint v[4]; - v[0] = v0; - v[1] = v1; - v[2] = v2; - v[3] = v3; - ctx->Driver.Uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC4); -} - -void GLAPIENTRY -_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_UNSIGNED_INT); -} - -void GLAPIENTRY -_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC2); -} - -void GLAPIENTRY -_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC3); -} - -void GLAPIENTRY -_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.Uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC4); -} - - - -void GLAPIENTRY -_mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose, - const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 2, 2, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose, - const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 3, 3, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose, - const GLfloat * value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 4, 4, location, count, transpose, value); -} - - -/** - * Non-square UniformMatrix are OpenGL 2.1 - */ -void GLAPIENTRY -_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 2, 3, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 3, 2, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 2, 4, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 4, 2, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 3, 4, location, count, transpose, value); -} - -void GLAPIENTRY -_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.UniformMatrix(ctx, 4, 3, location, count, transpose, value); -} - - -void GLAPIENTRY -_mesa_UseProgramObjectARB(GLhandleARB program) -{ - GET_CURRENT_CONTEXT(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->Driver.UseProgram(ctx, program); -} - - -void GLAPIENTRY -_mesa_ValidateProgramARB(GLhandleARB program) -{ - GET_CURRENT_CONTEXT(ctx); - ctx->Driver.ValidateProgram(ctx, program); -} - -#if FEATURE_ES2 - -void GLAPIENTRY -_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, - GLint* range, GLint* precision) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); -} - - -void GLAPIENTRY -_mesa_ReleaseShaderCompiler(void) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); -} - - -void GLAPIENTRY -_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, - const void* binary, GLint length) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); -} - -#endif - - -/** - * Plug in shader-related functions into API dispatch table. - */ -void -_mesa_init_shader_dispatch(struct _glapi_table *exec) -{ -#if FEATURE_GL - /* GL_ARB_vertex/fragment_shader */ - SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB); - SET_GetHandleARB(exec, _mesa_GetHandleARB); - SET_DetachObjectARB(exec, _mesa_DetachObjectARB); - SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB); - SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB); - SET_CompileShaderARB(exec, _mesa_CompileShaderARB); - SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB); - SET_AttachObjectARB(exec, _mesa_AttachObjectARB); - SET_LinkProgramARB(exec, _mesa_LinkProgramARB); - SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB); - SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB); - SET_Uniform1fARB(exec, _mesa_Uniform1fARB); - SET_Uniform2fARB(exec, _mesa_Uniform2fARB); - SET_Uniform3fARB(exec, _mesa_Uniform3fARB); - SET_Uniform4fARB(exec, _mesa_Uniform4fARB); - SET_Uniform1iARB(exec, _mesa_Uniform1iARB); - SET_Uniform2iARB(exec, _mesa_Uniform2iARB); - SET_Uniform3iARB(exec, _mesa_Uniform3iARB); - SET_Uniform4iARB(exec, _mesa_Uniform4iARB); - SET_Uniform1fvARB(exec, _mesa_Uniform1fvARB); - SET_Uniform2fvARB(exec, _mesa_Uniform2fvARB); - SET_Uniform3fvARB(exec, _mesa_Uniform3fvARB); - SET_Uniform4fvARB(exec, _mesa_Uniform4fvARB); - SET_Uniform1ivARB(exec, _mesa_Uniform1ivARB); - SET_Uniform2ivARB(exec, _mesa_Uniform2ivARB); - SET_Uniform3ivARB(exec, _mesa_Uniform3ivARB); - SET_Uniform4ivARB(exec, _mesa_Uniform4ivARB); - SET_UniformMatrix2fvARB(exec, _mesa_UniformMatrix2fvARB); - SET_UniformMatrix3fvARB(exec, _mesa_UniformMatrix3fvARB); - SET_UniformMatrix4fvARB(exec, _mesa_UniformMatrix4fvARB); - SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB); - SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB); - SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB); - SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB); - SET_GetUniformLocationARB(exec, _mesa_GetUniformLocationARB); - SET_GetActiveUniformARB(exec, _mesa_GetActiveUniformARB); - SET_GetUniformfvARB(exec, _mesa_GetUniformfvARB); - SET_GetUniformivARB(exec, _mesa_GetUniformivARB); - SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB); - - /* OpenGL 2.0 */ - SET_AttachShader(exec, _mesa_AttachShader); - SET_CreateProgram(exec, _mesa_CreateProgram); - SET_CreateShader(exec, _mesa_CreateShader); - SET_DeleteProgram(exec, _mesa_DeleteProgram); - SET_DeleteShader(exec, _mesa_DeleteShader); - SET_DetachShader(exec, _mesa_DetachShader); - SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders); - SET_GetProgramiv(exec, _mesa_GetProgramiv); - SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog); - SET_GetShaderiv(exec, _mesa_GetShaderiv); - SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog); - SET_IsProgram(exec, _mesa_IsProgram); - SET_IsShader(exec, _mesa_IsShader); - - /* OpenGL 2.1 */ - SET_UniformMatrix2x3fv(exec, _mesa_UniformMatrix2x3fv); - SET_UniformMatrix3x2fv(exec, _mesa_UniformMatrix3x2fv); - SET_UniformMatrix2x4fv(exec, _mesa_UniformMatrix2x4fv); - SET_UniformMatrix4x2fv(exec, _mesa_UniformMatrix4x2fv); - SET_UniformMatrix3x4fv(exec, _mesa_UniformMatrix3x4fv); - SET_UniformMatrix4x3fv(exec, _mesa_UniformMatrix4x3fv); - -#if FEATURE_ARB_vertex_shader - SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB); - SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB); - SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB); -#endif - - /* OpenGL 3.0 */ - /* XXX finish dispatch */ - (void) _mesa_Uniform1ui; - (void) _mesa_Uniform2ui; - (void) _mesa_Uniform3ui; - (void) _mesa_Uniform4ui; - (void) _mesa_Uniform1uiv; - (void) _mesa_Uniform2uiv; - (void) _mesa_Uniform3uiv; - (void) _mesa_Uniform4uiv; -#endif /* FEATURE_GL */ -} diff --git a/src/mesa/main/shaders.h b/src/mesa/main/shaders.h deleted file mode 100644 index af65b2d01a7..00000000000 --- a/src/mesa/main/shaders.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2004-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef SHADERS_H -#define SHADERS_H - - -#include "glheader.h" -#include "mtypes.h" - -extern void -_mesa_init_shader_dispatch(struct _glapi_table *exec); - -extern void GLAPIENTRY -_mesa_DeleteObjectARB(GLhandleARB obj); - -extern GLhandleARB GLAPIENTRY -_mesa_GetHandleARB(GLenum pname); - -extern void GLAPIENTRY -_mesa_DetachObjectARB (GLhandleARB, GLhandleARB); - -extern GLhandleARB GLAPIENTRY -_mesa_CreateShaderObjectARB (GLenum); - -extern void GLAPIENTRY -_mesa_ShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); - -extern void GLAPIENTRY -_mesa_CompileShaderARB (GLhandleARB); - -extern GLhandleARB GLAPIENTRY -_mesa_CreateProgramObjectARB (void); - -extern void GLAPIENTRY -_mesa_AttachObjectARB (GLhandleARB, GLhandleARB); - -extern void GLAPIENTRY -_mesa_LinkProgramARB (GLhandleARB); - -extern void GLAPIENTRY -_mesa_UseProgramObjectARB (GLhandleARB); - -extern void GLAPIENTRY -_mesa_ValidateProgramARB (GLhandleARB); - -extern void GLAPIENTRY -_mesa_Uniform1fARB (GLint, GLfloat); - -extern void GLAPIENTRY -_mesa_Uniform2fARB (GLint, GLfloat, GLfloat); - -extern void GLAPIENTRY -_mesa_Uniform3fARB (GLint, GLfloat, GLfloat, GLfloat); - -extern void GLAPIENTRY -_mesa_Uniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat); - -extern void GLAPIENTRY -_mesa_Uniform1iARB (GLint, GLint); - -extern void GLAPIENTRY -_mesa_Uniform2iARB (GLint, GLint, GLint); - -extern void GLAPIENTRY -_mesa_Uniform3iARB (GLint, GLint, GLint, GLint); - -extern void GLAPIENTRY -_mesa_Uniform4iARB (GLint, GLint, GLint, GLint, GLint); - -extern void GLAPIENTRY -_mesa_Uniform1fvARB (GLint, GLsizei, const GLfloat *); - -extern void GLAPIENTRY -_mesa_Uniform2fvARB (GLint, GLsizei, const GLfloat *); - -extern void GLAPIENTRY -_mesa_Uniform3fvARB (GLint, GLsizei, const GLfloat *); - -extern void GLAPIENTRY -_mesa_Uniform4fvARB (GLint, GLsizei, const GLfloat *); - -extern void GLAPIENTRY -_mesa_Uniform1ivARB (GLint, GLsizei, const GLint *); - -extern void GLAPIENTRY -_mesa_Uniform2ivARB (GLint, GLsizei, const GLint *); - -extern void GLAPIENTRY -_mesa_Uniform3ivARB (GLint, GLsizei, const GLint *); - -extern void GLAPIENTRY -_mesa_Uniform4ivARB (GLint, GLsizei, const GLint *); - -extern void GLAPIENTRY -_mesa_Uniform1ui(GLint location, GLuint v0); - -extern void GLAPIENTRY -_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1); - -extern void GLAPIENTRY -_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); - -extern void GLAPIENTRY -_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); - -extern void GLAPIENTRY -_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value); - -extern void GLAPIENTRY -_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value); - -extern void GLAPIENTRY -_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value); - -extern void GLAPIENTRY -_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value); - - -extern void GLAPIENTRY -_mesa_UniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *); - -extern void GLAPIENTRY -_mesa_UniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *); - -extern void GLAPIENTRY -_mesa_UniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *); - -extern void GLAPIENTRY -_mesa_GetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *); - -extern void GLAPIENTRY -_mesa_GetObjectParameterivARB (GLhandleARB, GLenum, GLint *); - -extern void GLAPIENTRY -_mesa_GetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); - -extern void GLAPIENTRY -_mesa_GetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); - -extern GLint GLAPIENTRY -_mesa_GetUniformLocationARB (GLhandleARB, const GLcharARB *); - -extern void GLAPIENTRY -_mesa_GetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); - -extern void GLAPIENTRY -_mesa_GetUniformfvARB (GLhandleARB, GLint, GLfloat *); - -extern void GLAPIENTRY -_mesa_GetUniformivARB (GLhandleARB, GLint, GLint *); - -extern void GLAPIENTRY -_mesa_GetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); - -#if FEATURE_ARB_vertex_shader - -extern void GLAPIENTRY -_mesa_BindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *); - -extern void GLAPIENTRY -_mesa_GetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); - -extern GLint GLAPIENTRY -_mesa_GetAttribLocationARB (GLhandleARB, const GLcharARB *); - -#endif /* FEATURE_ARB_vertex_shader */ - - -/* 2.0 */ -extern void GLAPIENTRY -_mesa_AttachShader(GLuint program, GLuint shader); - -extern GLuint GLAPIENTRY -_mesa_CreateShader(GLenum); - -extern GLuint GLAPIENTRY -_mesa_CreateProgram(void); - -extern void GLAPIENTRY -_mesa_DeleteProgram(GLuint program); - -extern void GLAPIENTRY -_mesa_DeleteShader(GLuint shader); - -extern void GLAPIENTRY -_mesa_DetachShader(GLuint program, GLuint shader); - -extern void GLAPIENTRY -_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj); - -extern void GLAPIENTRY -_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params); - -extern void GLAPIENTRY -_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, - GLsizei *length, GLchar *infoLog); - -extern void GLAPIENTRY -_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params); - -extern void GLAPIENTRY -_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, - GLsizei *length, GLchar *infoLog); - -extern GLboolean GLAPIENTRY -_mesa_IsProgram(GLuint program); - -extern GLboolean GLAPIENTRY -_mesa_IsShader(GLuint shader); - - - -/* 2.1 */ -extern void GLAPIENTRY -_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -extern void GLAPIENTRY -_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -extern void GLAPIENTRY -_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -extern void GLAPIENTRY -_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -extern void GLAPIENTRY -_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -extern void GLAPIENTRY -_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); - -/* GLES 2.0 */ -extern void GLAPIENTRY -_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, - GLint* range, GLint* precision); - -extern void GLAPIENTRY -_mesa_ReleaseShaderCompiler(void); - -extern void GLAPIENTRY -_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, - const void* binary, GLint length); - -#endif /* SHADERS_H */ diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c index e364e24048f..f9d10f3bbea 100644 --- a/src/mesa/main/shared.c +++ b/src/mesa/main/shared.c @@ -33,14 +33,14 @@ #include "mtypes.h" #include "hash.h" #include "arrayobj.h" +#if FEATURE_ATI_fragment_shader +#include "atifragshader.h" +#endif #include "bufferobj.h" #include "shared.h" -#include "shader/program.h" -#include "shader/shader_api.h" +#include "program/program.h" #include "dlist.h" -#if FEATURE_ATI_fragment_shader -#include "shader/atifragshader.h" -#endif +#include "shaderobj.h" #if FEATURE_ARB_sync #include "syncobj.h" #endif @@ -228,12 +228,12 @@ delete_shader_cb(GLuint id, void *data, void *userData) GLcontext *ctx = (GLcontext *) userData; struct gl_shader *sh = (struct gl_shader *) data; if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER) { - _mesa_free_shader(ctx, sh); + ctx->Driver.DeleteShader(ctx, sh); } else { struct gl_shader_program *shProg = (struct gl_shader_program *) data; ASSERT(shProg->Type == GL_SHADER_PROGRAM_MESA); - _mesa_free_shader_program(ctx, shProg); + ctx->Driver.DeleteShaderProgram(ctx, shProg); } } diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index b971cc976ee..2239ea4a85b 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -41,8 +41,8 @@ #include "light.h" #include "matrix.h" #include "pixel.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" +#include "program/program.h" +#include "program/prog_parameter.h" #include "state.h" #include "stencil.h" #include "texenvprogram.h" diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 964ba13c700..30963bdf7d0 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -28,13 +28,13 @@ #include "glheader.h" #include "imports.h" -#include "shader/program.h" -#include "shader/prog_parameter.h" -#include "shader/prog_cache.h" -#include "shader/prog_instruction.h" -#include "shader/prog_print.h" -#include "shader/prog_statevars.h" -#include "shader/programopt.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_print.h" +#include "program/prog_statevars.h" +#include "program/programopt.h" #include "texenvprogram.h" diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index de37e340393..1df165cf6a8 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -40,7 +40,7 @@ #include "teximage.h" #include "texobj.h" #include "mtypes.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c index ca03404f12f..745a0aeec9d 100644 --- a/src/mesa/main/texparam.c +++ b/src/mesa/main/texparam.c @@ -39,7 +39,7 @@ #include "main/texparam.h" #include "main/teximage.h" #include "main/texstate.h" -#include "shader/prog_instruction.h" +#include "program/prog_instruction.h" /** diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index fce17c2b660..dae173d1bde 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -528,7 +528,7 @@ update_texture_state( GLcontext *ctx ) /* Get the bitmask of texture target enables. * enableBits will be a mask of the TEXTURE_*_BIT flags indicating * which texture targets are enabled (fixed function) or referenced - * by a fragment shader/program. When multiple flags are set, we'll + * by a fragment program/program. When multiple flags are set, we'll * settle on the one with highest priority (see below). */ if (vprog) { diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c index 050ebf02701..6126f1286d8 100644 --- a/src/mesa/main/transformfeedback.c +++ b/src/mesa/main/transformfeedback.c @@ -35,10 +35,12 @@ #include "context.h" #include "hash.h" #include "transformfeedback.h" +#include "shaderapi.h" +#include "shaderobj.h" #include "main/dispatch.h" -#include "shader/prog_parameter.h" -#include "shader/shader_api.h" +#include "program/prog_parameter.h" +//#include "program/shader_api.h" #if FEATURE_EXT_transform_feedback diff --git a/src/mesa/main/uniforms.c b/src/mesa/main/uniforms.c new file mode 100644 index 00000000000..aac4177f408 --- /dev/null +++ b/src/mesa/main/uniforms.c @@ -0,0 +1,1334 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file uniforms.c + * Functions related to GLSL uniform variables. + * \author Brian Paul + */ + +/** + * XXX things to do: + * 1. Check that the right error code is generated for all _mesa_error() calls. + * 2. Insert FLUSH_VERTICES calls in various places + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/dispatch.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "main/uniforms.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" +#include "program/prog_uniform.h" + + + +static GLenum +base_uniform_type(GLenum type) +{ + switch (type) { +#if 0 /* not needed, for now */ + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_BOOL; +#endif + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + return GL_FLOAT; + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_VEC2: + case GL_UNSIGNED_INT_VEC3: + case GL_UNSIGNED_INT_VEC4: + return GL_UNSIGNED_INT; + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return GL_INT; + default: + _mesa_problem(NULL, "Invalid type in base_uniform_type()"); + return GL_FLOAT; + } +} + + +static GLboolean +is_boolean_type(GLenum type) +{ + switch (type) { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +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: + case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +static struct gl_program_parameter * +get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index) +{ + const struct gl_program *prog = NULL; + GLint progPos; + + 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; + } + } + + if (!prog || progPos < 0) + return NULL; /* should never happen */ + + return &prog->Parameters->Parameters[progPos]; +} + + +/** + * Called by glGetActiveUniform(). + */ +static void +_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; + const struct gl_program *prog = NULL; + const struct gl_program_parameter *param; + GLint progPos; + + 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)"); + return; + } + + 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; + } + } + + if (!prog || progPos < 0) + return; /* should never happen */ + + ASSERT(progPos < prog->Parameters->NumParameters); + param = &prog->Parameters->Parameters[progPos]; + + if (nameOut) { + _mesa_copy_string(nameOut, maxLength, length, param->Name); + } + + if (size) { + GLint typeSize = _mesa_sizeof_glsl_type(param->DataType); + if ((GLint) param->Size > typeSize) { + /* This is an array. + * Array elements are placed on vector[4] boundaries so they're + * a multiple of four floats. We round typeSize up to next multiple + * of four to get the right size below. + */ + typeSize = (typeSize + 3) & ~3; + } + /* Note that the returned size is in units of the <type>, not bytes */ + *size = param->Size / typeSize; + } + + if (type) { + *type = param->DataType; + } +} + + + +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; + } +} + + +/** + * Determine the number of rows and columns occupied by a uniform + * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4), + * the number of rows = 1 and cols = number of elements in the vector. + */ +static void +get_uniform_rows_cols(const struct gl_program_parameter *p, + GLint *rows, GLint *cols) +{ + get_matrix_dims(p->DataType, rows, cols); + if (*rows == 0 && *cols == 0) { + /* not a matrix type, probably a float or vector */ + if (p->Size <= 4) { + *rows = 1; + *cols = p->Size; + } + else { + *rows = p->Size / 4 + 1; + if (p->Size % 4 == 0) + *cols = 4; + else + *cols = p->Size % 4; + } + } +} + + +/** + * Helper for get_uniform[fi]v() functions. + * Given a shader program name and uniform location, return a pointer + * to the shader program and return the program parameter position. + */ +static void +lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location, + struct gl_program **progOut, GLint *paramPosOut) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v"); + struct gl_program *prog = NULL; + GLint progPos = -1; + + /* if shProg is NULL, we'll have already recorded an error */ + + if (shProg) { + if (!shProg->Uniforms || + location < 0 || + location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)"); + } + else { + /* OK, find the gl_program and program parameter location */ + 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; + } + } + } + } + + *progOut = prog; + *paramPosOut = progPos; +} + + +/** + * GLGL uniform arrays and structs require special handling. + * + * The GL_ARB_shader_objects spec says that if you use + * glGetUniformLocation to get the location of an array, you CANNOT + * access other elements of the array by adding an offset to the + * returned location. For example, you must call + * glGetUniformLocation("foo[16]") if you want to set the 16th element + * of the array with glUniform(). + * + * HOWEVER, some other OpenGL drivers allow accessing array elements + * by adding an offset to the returned array location. And some apps + * seem to depend on that behaviour. + * + * Mesa's gl_uniform_list doesn't directly support this since each + * entry in the list describes one uniform variable, not one uniform + * element. We could insert dummy entries in the list for each array + * element after [0] but that causes complications elsewhere. + * + * We solve this problem by encoding two values in the location that's + * returned by glGetUniformLocation(): + * a) index into gl_uniform_list::Uniforms[] for the uniform + * b) an array/field offset (0 for simple types) + * + * These two values are encoded in the high and low halves of a GLint. + * By putting the uniform number in the high part and the offset in the + * low part, we can support the unofficial ability to index into arrays + * by adding offsets to the location value. + */ +static void +merge_location_offset(GLint *location, GLint offset) +{ + *location = (*location << 16) | offset; +} + + +/** + * Separate the uniform location and parameter offset. See above. + */ +static void +split_location_offset(GLint *location, GLint *offset) +{ + *offset = *location & 0xffff; + *location = *location >> 16; +} + + + +/** + * Called via glGetUniformfv(). + */ +static void +_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, + GLfloat *params) +{ + struct gl_program *prog; + GLint paramPos; + GLint offset; + + split_location_offset(&location, &offset); + + lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos); + + if (prog) { + const struct gl_program_parameter *p = + &prog->Parameters->Parameters[paramPos]; + GLint rows, cols, i, j, k; + + get_uniform_rows_cols(p, &rows, &cols); + + k = 0; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++ ) { + params[k++] = prog->Parameters->ParameterValues[paramPos+i][j]; + } + } + } +} + + +/** + * Called via glGetUniformiv(). + * \sa _mesa_get_uniformfv, only difference is a cast. + */ +static void +_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location, + GLint *params) +{ + struct gl_program *prog; + GLint paramPos; + GLint offset; + + split_location_offset(&location, &offset); + + lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos); + + if (prog) { + const struct gl_program_parameter *p = + &prog->Parameters->Parameters[paramPos]; + GLint rows, cols, i, j, k; + + get_uniform_rows_cols(p, &rows, &cols); + + k = 0; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++ ) { + params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j]; + } + } + } +} + + +/** + * Called via glGetUniformLocation(). + * + * The return value will encode two values, the uniform location and an + * offset (used for arrays, structs). + */ +static GLint +_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) +{ + GLint offset = 0, location = -1; + + 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. + */ + + /* XXX we need to be able to parse uniform names for structs and arrays + * such as: + * mymatrix[1] + * mystruct.field1 + */ + + { + /* handle 1-dimension arrays here... */ + char *c = strchr(name, '['); + if (c) { + /* truncate name at [ */ + const GLint len = c - name; + GLchar *newName = malloc(len + 1); + if (!newName) + return -1; /* out of mem */ + memcpy(newName, name, len); + newName[len] = 0; + + location = _mesa_lookup_uniform(shProg->Uniforms, newName); + if (location >= 0) { + const GLint element = atoi(c + 1); + if (element > 0) { + /* get type of the uniform array element */ + struct gl_program_parameter *p; + p = get_uniform_parameter(shProg, location); + if (p) { + GLint rows, cols; + get_matrix_dims(p->DataType, &rows, &cols); + if (rows < 1) + rows = 1; + offset = element * rows; + } + } + } + + free(newName); + } + } + + if (location < 0) { + location = _mesa_lookup_uniform(shProg->Uniforms, name); + } + + if (location >= 0) { + merge_location_offset(&location, offset); + } + + return location; +} + + + +/** + * Update the vertex/fragment program's TexturesUsed array. + * + * This needs to be called after glUniform(set sampler var) is called. + * A call to glUniform(samplerVar, value) causes a sampler to point to a + * particular texture unit. We know the sampler's texture target + * (1D/2D/3D/etc) from compile time but the sampler's texture unit is + * set by glUniform() calls. + * + * So, scan the program->SamplerUnits[] and program->SamplerTargets[] + * information to update the prog->TexturesUsed[] values. + * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX, + * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc. + * We'll use that info for state validation before rendering. + */ +void +_mesa_update_shader_textures_used(struct gl_program *prog) +{ + GLuint s; + + memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed)); + + for (s = 0; s < MAX_SAMPLERS; s++) { + if (prog->SamplersUsed & (1 << s)) { + GLuint unit = prog->SamplerUnits[s]; + GLuint tgt = prog->SamplerTargets[s]; + assert(unit < MAX_TEXTURE_IMAGE_UNITS); + assert(tgt < NUM_TEXTURE_TARGETS); + prog->TexturesUsed[unit] |= (1 << tgt); + } + } +} + + +/** + * 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_UNSIGNED_INT || + userType == GL_INT)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 || + userType == GL_UNSIGNED_INT_VEC2 || + userType == GL_INT_VEC2)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 || + userType == GL_UNSIGNED_INT_VEC3 || + userType == GL_INT_VEC3)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 || + userType == GL_UNSIGNED_INT_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 index the index of the program parameter for the uniform + * \param offset additional parameter slot offset (for arrays) + * \param type the incoming datatype of 'values' + * \param count the number of uniforms to set + * \param elems number of elements per uniform (1, 2, 3 or 4) + * \param values the new values, of datatype 'type' + */ +static void +set_program_uniform(GLcontext *ctx, struct gl_program *program, + GLint index, GLint offset, + GLenum type, GLsizei count, GLint elems, + const void *values) +{ + const struct gl_program_parameter *param = + &program->Parameters->Parameters[index]; + + assert(offset >= 0); + assert(elems >= 1); + assert(elems <= 4); + + if (!compatible_types(type, param->DataType)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); + return; + } + + if (index + offset > (GLint) program->Parameters->Size) { + /* out of bounds! */ + return; + } + + if (param->Type == PROGRAM_SAMPLER) { + /* This controls which texture unit which is used by a sampler */ + GLboolean changed = GL_FALSE; + GLint i; + + /* this should have been caught by the compatible_types() check */ + ASSERT(type == GL_INT); + + /* loop over number of samplers to change */ + for (i = 0; i < count; i++) { + GLuint sampler = + (GLuint) program->Parameters->ParameterValues[index + offset + i][0]; + GLuint texUnit = ((GLuint *) values)[i]; + + /* check that the sampler (tex unit index) is legal */ + if (texUnit >= ctx->Const.MaxTextureImageUnits) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glUniform1(invalid sampler/tex unit index for '%s')", + param->Name); + return; + } + + /* This maps a sampler to a texture unit: */ + if (sampler < MAX_SAMPLERS) { +#if 0 + printf("Set program %p sampler %d '%s' to unit %u\n", + program, sampler, param->Name, texUnit); +#endif + if (program->SamplerUnits[sampler] != texUnit) { + program->SamplerUnits[sampler] = texUnit; + changed = GL_TRUE; + } + } + } + + if (changed) { + /* When a sampler's value changes it usually requires rewriting + * a GPU program's TEX instructions since there may not be a + * sampler->texture lookup table. We signal this with the + * ProgramStringNotify() callback. + */ + FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); + _mesa_update_shader_textures_used(program); + /* Do we need to care about the return value here? + * This should not be the first time the driver was notified of + * this program. + */ + (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program); + } + } + else { + /* ordinary uniform variable */ + const GLboolean isUniformBool = is_boolean_type(param->DataType); + const GLenum basicType = base_uniform_type(type); + const GLint slots = (param->Size + 3) / 4; + const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType); + GLsizei k, i; + + if ((GLint) param->Size > typeSize) { + /* an array */ + /* we'll ignore extra data below */ + } + else { + /* non-array: count must be at most one; count == 0 is handled by the loop below */ + if (count > 1) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform(uniform '%s' is not an array)", + param->Name); + return; + } + } + + /* loop over number of array elements */ + for (k = 0; k < count; k++) { + GLfloat *uniformVal; + + if (offset + k >= slots) { + /* Extra array data is ignored */ + break; + } + + /* uniformVal (the destination) is always float[4] */ + uniformVal = program->Parameters->ParameterValues[index + offset + k]; + + if (basicType == GL_INT) { + /* convert user's ints to floats */ + const GLint *iValues = ((const GLint *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = (GLfloat) iValues[i]; + } + } + else if (basicType == GL_UNSIGNED_INT) { + /* convert user's uints to floats */ + const GLuint *iValues = ((const GLuint *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = (GLfloat) iValues[i]; + } + } + else { + const GLfloat *fValues = ((const GLfloat *) values) + k * elems; + assert(basicType == GL_FLOAT); + for (i = 0; i < elems; i++) { + uniformVal[i] = fValues[i]; + } + } + + /* if the uniform is bool-valued, convert to 1.0 or 0.0 */ + if (isUniformBool) { + for (i = 0; i < elems; i++) { + uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f; + } + } + } + } +} + + +/** + * Called via glUniform*() functions. + */ +static void +_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, + const GLvoid *values, GLenum type) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + struct gl_uniform *uniform; + GLint elems, offset; + + 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 < -1) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)", + location); + return; + } + + split_location_offset(&location, &offset); + + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location); + return; + } + + if (count < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)"); + return; + } + + elems = _mesa_sizeof_glsl_type(type); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + uniform = &shProg->Uniforms->Uniforms[location]; + + if (ctx->Shader.Flags & GLSL_UNIFORMS) { + const GLenum basicType = base_uniform_type(type); + GLint i; + printf("Mesa: set program %u uniform %s (loc %d) to: ", + shProg->Name, uniform->Name, location); + if (basicType == GL_INT) { + const GLint *v = (const GLint *) values; + for (i = 0; i < count * elems; i++) { + printf("%d ", v[i]); + } + } + else if (basicType == GL_UNSIGNED_INT) { + const GLuint *v = (const GLuint *) values; + for (i = 0; i < count * elems; i++) { + printf("%u ", v[i]); + } + } + else { + const GLfloat *v = (const GLfloat *) values; + assert(basicType == GL_FLOAT); + for (i = 0; i < count * elems; i++) { + printf("%g ", v[i]); + } + } + printf("\n"); + } + + /* 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) { + /* convert uniform location to program parameter index */ + GLint index = uniform->VertPos; + if (index >= 0) { + set_program_uniform(ctx, &shProg->VertexProgram->Base, + index, offset, type, count, elems, values); + } + } + + if (shProg->FragmentProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->FragPos; + if (index >= 0) { + set_program_uniform(ctx, &shProg->FragmentProgram->Base, + index, offset, type, count, elems, values); + } + } + + uniform->Initialized = GL_TRUE; +} + + +/** + * Set a matrix-valued program parameter. + */ +static void +set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program, + GLuint index, GLuint offset, + GLuint count, GLuint rows, GLuint cols, + GLboolean transpose, const GLfloat *values) +{ + GLuint mat, row, col; + GLuint src = 0; + const struct gl_program_parameter * param = &program->Parameters->Parameters[index]; + const GLuint slots = (param->Size + 3) / 4; + const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType); + GLint nr, nc; + + /* check that the number of rows, columns is correct */ + get_matrix_dims(param->DataType, &nr, &nc); + if (rows != nr || cols != nc) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(matrix size mismatch)"); + return; + } + + if ((GLint) param->Size <= typeSize) { + /* non-array: count must be at most one; count == 0 is handled by the loop below */ + if (count > 1) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(uniform is not an array)"); + 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; + if (offset >= slots) { + /* Ignore writes beyond the end of (the used part of) an array */ + return; + } + v = program->Parameters->ParameterValues[index + offset]; + for (row = 0; row < rows; row++) { + if (transpose) { + v[row] = values[src + row * cols + col]; + } + else { + v[row] = values[src + col * rows + row]; + } + } + + offset++; + } + + src += rows * cols; /* next matrix */ + } +} + + +/** + * Called by glUniformMatrix*() functions. + * Note: cols=2, rows=4 ==> array[2] of vec4 + */ +static void +_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, + GLint location, GLsizei count, + GLboolean transpose, const GLfloat *values) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + struct gl_uniform *uniform; + GLint offset; + + if (!shProg || !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(program not linked)"); + return; + } + + if (location == -1) + return; /* The standard specifies this as a no-op */ + + if (location < -1) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)"); + return; + } + + split_location_offset(&location, &offset); + + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)"); + return; + } + if (values == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + uniform = &shProg->Uniforms->Uniforms[location]; + + if (shProg->VertexProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->VertPos; + if (index >= 0) { + set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base, + index, offset, + count, rows, cols, transpose, values); + } + } + + if (shProg->FragmentProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->FragPos; + if (index >= 0) { + set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base, + index, offset, + count, rows, cols, transpose, values); + } + } + + uniform->Initialized = GL_TRUE; +} + + +void GLAPIENTRY +_mesa_Uniform1fARB(GLint location, GLfloat v0) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, 1, &v0, GL_FLOAT); +} + +void GLAPIENTRY +_mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat v[2]; + v[0] = v0; + v[1] = v1; + _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat v[3]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, + GLfloat v3) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat v[4]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC4); +} + +void GLAPIENTRY +_mesa_Uniform1iARB(GLint location, GLint v0) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, 1, &v0, GL_INT); +} + +void GLAPIENTRY +_mesa_Uniform2iARB(GLint location, GLint v0, GLint v1) +{ + GET_CURRENT_CONTEXT(ctx); + GLint v[2]; + v[0] = v0; + v[1] = v1; + _mesa_uniform(ctx, location, 1, v, GL_INT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2) +{ + GET_CURRENT_CONTEXT(ctx); + GLint v[3]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + _mesa_uniform(ctx, location, 1, v, GL_INT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + GET_CURRENT_CONTEXT(ctx); + GLint v[4]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + _mesa_uniform(ctx, location, 1, v, GL_INT_VEC4); +} + +void GLAPIENTRY +_mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_FLOAT); +} + +void GLAPIENTRY +_mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC4); +} + +void GLAPIENTRY +_mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_INT); +} + +void GLAPIENTRY +_mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_INT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_INT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_INT_VEC4); +} + + +/** OpenGL 3.0 GLuint-valued functions **/ +void GLAPIENTRY +_mesa_Uniform1ui(GLint location, GLuint v0) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, 1, &v0, GL_UNSIGNED_INT); +} + +void GLAPIENTRY +_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint v[2]; + v[0] = v0; + v[1] = v1; + _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint v[3]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint v[4]; + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC4); +} + +void GLAPIENTRY +_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT); +} + +void GLAPIENTRY +_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC2); +} + +void GLAPIENTRY +_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC3); +} + +void GLAPIENTRY +_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC4); +} + + + +void GLAPIENTRY +_mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose, + const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 2, 2, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose, + const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 3, 3, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose, + const GLfloat * value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 4, 4, location, count, transpose, value); +} + + +/** + * Non-square UniformMatrix are OpenGL 2.1 + */ +void GLAPIENTRY +_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 2, 3, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 3, 2, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 2, 4, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 4, 2, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 3, 4, location, count, transpose, value); +} + +void GLAPIENTRY +_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_uniform_matrix(ctx, 4, 3, location, count, transpose, value); +} + + +void GLAPIENTRY +_mesa_GetUniformfvARB(GLhandleARB program, GLint location, GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_get_uniformfv(ctx, program, location, params); +} + + +void GLAPIENTRY +_mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_get_uniformiv(ctx, program, location, params); +} + + +GLint GLAPIENTRY +_mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name) +{ + GET_CURRENT_CONTEXT(ctx); + return _mesa_get_uniform_location(ctx, programObj, name); +} + + +void GLAPIENTRY +_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index, + GLsizei maxLength, GLsizei * length, GLint * size, + GLenum * type, GLcharARB * name) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_get_active_uniform(ctx, program, index, maxLength, length, size, + type, name); +} + + +/** + * Plug in shader uniform-related functions into API dispatch table. + */ +void +_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec) +{ + SET_Uniform1fARB(exec, _mesa_Uniform1fARB); + SET_Uniform2fARB(exec, _mesa_Uniform2fARB); + SET_Uniform3fARB(exec, _mesa_Uniform3fARB); + SET_Uniform4fARB(exec, _mesa_Uniform4fARB); + SET_Uniform1iARB(exec, _mesa_Uniform1iARB); + SET_Uniform2iARB(exec, _mesa_Uniform2iARB); + SET_Uniform3iARB(exec, _mesa_Uniform3iARB); + SET_Uniform4iARB(exec, _mesa_Uniform4iARB); + SET_Uniform1fvARB(exec, _mesa_Uniform1fvARB); + SET_Uniform2fvARB(exec, _mesa_Uniform2fvARB); + SET_Uniform3fvARB(exec, _mesa_Uniform3fvARB); + SET_Uniform4fvARB(exec, _mesa_Uniform4fvARB); + SET_Uniform1ivARB(exec, _mesa_Uniform1ivARB); + SET_Uniform2ivARB(exec, _mesa_Uniform2ivARB); + SET_Uniform3ivARB(exec, _mesa_Uniform3ivARB); + SET_Uniform4ivARB(exec, _mesa_Uniform4ivARB); + SET_UniformMatrix2fvARB(exec, _mesa_UniformMatrix2fvARB); + SET_UniformMatrix3fvARB(exec, _mesa_UniformMatrix3fvARB); + SET_UniformMatrix4fvARB(exec, _mesa_UniformMatrix4fvARB); + + SET_GetActiveUniformARB(exec, _mesa_GetActiveUniformARB); + SET_GetUniformLocationARB(exec, _mesa_GetUniformLocationARB); + SET_GetUniformfvARB(exec, _mesa_GetUniformfvARB); + SET_GetUniformivARB(exec, _mesa_GetUniformivARB); + + /* OpenGL 2.1 */ + SET_UniformMatrix2x3fv(exec, _mesa_UniformMatrix2x3fv); + SET_UniformMatrix3x2fv(exec, _mesa_UniformMatrix3x2fv); + SET_UniformMatrix2x4fv(exec, _mesa_UniformMatrix2x4fv); + SET_UniformMatrix4x2fv(exec, _mesa_UniformMatrix4x2fv); + SET_UniformMatrix3x4fv(exec, _mesa_UniformMatrix3x4fv); + SET_UniformMatrix4x3fv(exec, _mesa_UniformMatrix4x3fv); + + /* OpenGL 3.0 */ + /* XXX finish dispatch */ + (void) _mesa_Uniform1ui; + (void) _mesa_Uniform2ui; + (void) _mesa_Uniform3ui; + (void) _mesa_Uniform4ui; + (void) _mesa_Uniform1uiv; + (void) _mesa_Uniform2uiv; + (void) _mesa_Uniform3uiv; + (void) _mesa_Uniform4uiv; +} diff --git a/src/mesa/main/uniforms.h b/src/mesa/main/uniforms.h new file mode 100644 index 00000000000..29f77cb35a0 --- /dev/null +++ b/src/mesa/main/uniforms.h @@ -0,0 +1,158 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef UNIFORMS_H +#define UNIFORMS_H + + +extern void GLAPIENTRY +_mesa_Uniform1fARB(GLint, GLfloat); + +extern void GLAPIENTRY +_mesa_Uniform2fARB(GLint, GLfloat, GLfloat); + +extern void GLAPIENTRY +_mesa_Uniform3fARB(GLint, GLfloat, GLfloat, GLfloat); + +extern void GLAPIENTRY +_mesa_Uniform4fARB(GLint, GLfloat, GLfloat, GLfloat, GLfloat); + +extern void GLAPIENTRY +_mesa_Uniform1iARB(GLint, GLint); + +extern void GLAPIENTRY +_mesa_Uniform2iARB(GLint, GLint, GLint); + +extern void GLAPIENTRY +_mesa_Uniform3iARB(GLint, GLint, GLint, GLint); + +extern void GLAPIENTRY +_mesa_Uniform4iARB(GLint, GLint, GLint, GLint, GLint); + +extern void GLAPIENTRY +_mesa_Uniform1fvARB(GLint, GLsizei, const GLfloat *); + +extern void GLAPIENTRY +_mesa_Uniform2fvARB(GLint, GLsizei, const GLfloat *); + +extern void GLAPIENTRY +_mesa_Uniform3fvARB(GLint, GLsizei, const GLfloat *); + +extern void GLAPIENTRY +_mesa_Uniform4fvARB(GLint, GLsizei, const GLfloat *); + +extern void GLAPIENTRY +_mesa_Uniform1ivARB(GLint, GLsizei, const GLint *); + +extern void GLAPIENTRY +_mesa_Uniform2ivARB(GLint, GLsizei, const GLint *); + +extern void GLAPIENTRY +_mesa_Uniform3ivARB(GLint, GLsizei, const GLint *); + +extern void GLAPIENTRY +_mesa_Uniform4ivARB(GLint, GLsizei, const GLint *); + +extern void GLAPIENTRY +_mesa_Uniform1ui(GLint location, GLuint v0); + +extern void GLAPIENTRY +_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1); + +extern void GLAPIENTRY +_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); + +extern void GLAPIENTRY +_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); + +extern void GLAPIENTRY +_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value); + +extern void GLAPIENTRY +_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value); + +extern void GLAPIENTRY +_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value); + +extern void GLAPIENTRY +_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value); + + +extern void GLAPIENTRY +_mesa_UniformMatrix2fvARB(GLint, GLsizei, GLboolean, const GLfloat *); + +extern void GLAPIENTRY +_mesa_UniformMatrix3fvARB(GLint, GLsizei, GLboolean, const GLfloat *); + +extern void GLAPIENTRY +_mesa_UniformMatrix4fvARB(GLint, GLsizei, GLboolean, const GLfloat *); + +extern void GLAPIENTRY +_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + +extern void GLAPIENTRY +_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + +extern void GLAPIENTRY +_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + +extern void GLAPIENTRY +_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + +extern void GLAPIENTRY +_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + +extern void GLAPIENTRY +_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, + const GLfloat *value); + + +extern void GLAPIENTRY +_mesa_GetActiveUniformARB(GLhandleARB, GLuint, GLsizei, GLsizei *, + GLint *, GLenum *, GLcharARB *); + +extern void GLAPIENTRY +_mesa_GetUniformfvARB(GLhandleARB, GLint, GLfloat *); + +extern void GLAPIENTRY +_mesa_GetUniformivARB(GLhandleARB, GLint, GLint *); + +extern GLint GLAPIENTRY +_mesa_GetUniformLocationARB(GLhandleARB, const GLcharARB *); + + + +extern void +_mesa_update_shader_textures_used(struct gl_program *prog); + + +extern void +_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec); + +#endif /* UNIFORMS_H */ |