From: Brian Paul Date: Sun, 31 Aug 2003 18:52:47 +0000 (+0000) Subject: Moved some shared vertex/fragment program code into new program.c file. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=04a81da03bef5020d863e46aa597eddf7aaac016;p=mesa.git Moved some shared vertex/fragment program code into new program.c file. Implemented new program_parameter_list type and functions for dealing with named program parameters, constants and GL state references. New state_index enum for describing GL state referenced within ARB vertex/ fragment programs. Plus, functions for fetching named GL state. --- diff --git a/src/mesa/main/Makefile.X11 b/src/mesa/main/Makefile.X11 index d918656c146..1f9bd666d5d 100644 --- a/src/mesa/main/Makefile.X11 +++ b/src/mesa/main/Makefile.X11 @@ -62,6 +62,7 @@ CORE_SOURCES = \ pixel.c \ points.c \ polygon.c \ + program.c \ rastpos.c \ state.c \ stencil.c \ diff --git a/src/mesa/main/arbfragparse.h b/src/mesa/main/arbfragparse.h index ad6d8efe4a4..17e8dcf6239 100644 --- a/src/mesa/main/arbfragparse.h +++ b/src/mesa/main/arbfragparse.h @@ -25,6 +25,8 @@ #ifndef ARBFRAGPARSE_H #define ARBFRAGPARSE_H +#include "mtypes.h" + extern void _mesa_parse_arb_fragment_program(GLcontext * ctx, GLenum target, const GLubyte * str, GLsizei len, diff --git a/src/mesa/main/arbprogram.c b/src/mesa/main/arbprogram.c index 07ba4622197..4e40d278343 100644 --- a/src/mesa/main/arbprogram.c +++ b/src/mesa/main/arbprogram.c @@ -44,40 +44,6 @@ #include "nvvertprog.h" -/* - * Init context's program state - */ -void -_mesa_init_program(GLcontext *ctx) -{ - GLuint i; - - ctx->Program.ErrorPos = -1; - ctx->Program.ErrorString = _mesa_strdup(""); - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - ctx->VertexProgram.Enabled = GL_FALSE; - ctx->VertexProgram.PointSizeEnabled = GL_FALSE; - ctx->VertexProgram.TwoSideEnabled = GL_FALSE; - ctx->VertexProgram.Current = NULL; - ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram; - assert(ctx->VertexProgram.Current); - ctx->VertexProgram.Current->Base.RefCount++; - for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { - ctx->VertexProgram.TrackMatrix[i] = GL_NONE; - ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; - } -#endif - -#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program - ctx->FragmentProgram.Enabled = GL_FALSE; - ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram; - assert(ctx->FragmentProgram.Current); - ctx->FragmentProgram.Current->Base.RefCount++; -#endif -} - - void _mesa_EnableVertexAttribArrayARB(GLuint index) { diff --git a/src/mesa/main/arbprogram.h b/src/mesa/main/arbprogram.h index 07cd3a17aa1..bc5a6626ed5 100644 --- a/src/mesa/main/arbprogram.h +++ b/src/mesa/main/arbprogram.h @@ -26,11 +26,6 @@ #ifndef ARBPROGRAM_H #define ARBPROGRAM_H -#include "mtypes.h" - -extern void -_mesa_init_program(GLcontext *ctx); - extern void _mesa_EnableVertexAttribArrayARB(GLuint index); diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 8e5884a6cb9..9151c74899f 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -74,7 +74,6 @@ #include "glheader.h" #include "imports.h" #include "accum.h" -#include "arbprogram.h" #include "attrib.h" #include "blend.h" #include "buffers.h" @@ -111,8 +110,8 @@ #include "texstate.h" #include "mtypes.h" #include "varray.h" -#if FEATURE_NV_vertex_program -#include "nvprogram.h" +#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program +#include "program.h" #endif #include "vtxfmt.h" #if _HAVE_FULL_GL diff --git a/src/mesa/main/descrip.mms b/src/mesa/main/descrip.mms index 9cff58e8ffc..41b5fe52e2b 100644 --- a/src/mesa/main/descrip.mms +++ b/src/mesa/main/descrip.mms @@ -59,6 +59,7 @@ SOURCES =accum.c \ pixel.c \ points.c \ polygon.c \ + program.c \ rastpos.c \ state.c \ stencil.c \ @@ -116,6 +117,7 @@ occlude.obj,\ pixel.obj,\ points.obj,\ polygon.obj,\ +program.obj,\ rastpos.obj,\ state.obj,\ stencil.obj,\ @@ -187,6 +189,7 @@ occlude.obj : occlude.c pixel.obj : pixel.c points.obj : points.c polygon.obj : polygon.c +program.obj : program.c rastpos.obj : rastpos.c state.obj : state.c stencil.obj : stencil.c diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index abfc2dfff88..36809fbe578 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -34,6 +34,7 @@ #include "config.h" #if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program #include "arbprogram.h" +#include "program.h" #endif #include "attrib.h" #include "blend.h" @@ -71,6 +72,7 @@ #include "varray.h" #if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program #include "nvprogram.h" +#include "program.h" #endif #include "math/m_matrix.h" @@ -6509,9 +6511,9 @@ _mesa_init_dlist_table( struct _glapi_table *table, GLuint tableSize ) * VertexAttribPointerNV, GetProgram*, GetVertexAttrib* */ table->BindProgramNV = save_BindProgramNV; - table->DeleteProgramsNV = _mesa_DeleteProgramsNV; + table->DeleteProgramsNV = _mesa_DeletePrograms; table->ExecuteProgramNV = save_ExecuteProgramNV; - table->GenProgramsNV = _mesa_GenProgramsNV; + table->GenProgramsNV = _mesa_GenPrograms; table->AreProgramsResidentNV = _mesa_AreProgramsResidentNV; table->RequestResidentProgramsNV = save_RequestResidentProgramsNV; table->GetProgramParameterfvNV = _mesa_GetProgramParameterfvNV; @@ -6523,7 +6525,7 @@ _mesa_init_dlist_table( struct _glapi_table *table, GLuint tableSize ) table->GetVertexAttribfvNV = _mesa_GetVertexAttribfvNV; table->GetVertexAttribivNV = _mesa_GetVertexAttribivNV; table->GetVertexAttribPointervNV = _mesa_GetVertexAttribPointervNV; - table->IsProgramNV = _mesa_IsProgramNV; + table->IsProgramNV = _mesa_IsProgram; table->LoadProgramNV = save_LoadProgramNV; table->ProgramParameter4dNV = save_ProgramParameter4dNV; table->ProgramParameter4dvNV = save_ProgramParameter4dvNV; diff --git a/src/mesa/main/main.dsp b/src/mesa/main/main.dsp index 72d7edd5cb7..9f1537fd53d 100644 --- a/src/mesa/main/main.dsp +++ b/src/mesa/main/main.dsp @@ -265,6 +265,10 @@ SOURCE=.\polygon.c # End Source File # Begin Source File +SOURCE=.\program.c +# End Source File +# Begin Source File + SOURCE=.\rastpos.c # End Source File # Begin Source File @@ -525,6 +529,10 @@ SOURCE=.\polygon.h # End Source File # Begin Source File +SOURCE=.\program.h +# End Source File +# Begin Source File + SOURCE=.\rastpos.h # End Source File # Begin Source File diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 5497aac8380..47cb19b6259 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1445,16 +1445,7 @@ enum register_file struct vp_instruction; struct fp_instruction; - -/** - * Named program parameters - */ -struct program_parameter -{ - const char *Name; - GLfloat Values[4]; - GLboolean Constant; -}; +struct program_parameter_list; /** @@ -1499,8 +1490,7 @@ struct fragment_program GLuint NumAluInstructions; /**< GL_ARB_fragment_program */ GLuint NumTexInstructions; GLuint NumTexIndirections; - struct program_parameter *Parameters; /**< array [NumParameters] */ - GLuint NumParameters; + struct program_parameter_list *Parameters; /**< array [NumParameters] */ }; diff --git a/src/mesa/main/nvfragparse.c b/src/mesa/main/nvfragparse.c index 36840d0e753..cf631a5e184 100644 --- a/src/mesa/main/nvfragparse.c +++ b/src/mesa/main/nvfragparse.c @@ -37,6 +37,7 @@ #include "nvfragprog.h" #include "nvfragparse.h" #include "nvprogram.h" +#include "program.h" #define INPUT_1V 1 @@ -136,11 +137,7 @@ struct parse_state { const GLubyte *curLine; struct fragment_program *program; /* current program */ - GLuint numParameters; - struct program_parameter *parameters; /* DECLARE */ - - GLuint numConstants; - struct program_parameter *constants; /* DEFINE */ + struct program_parameter_list *parameters; GLuint numInst; /* number of instructions parsed */ GLuint inputsRead; /* bitmask of input registers used */ @@ -149,69 +146,6 @@ struct parse_state { }; -/** - * Add a new program parameter (via DEFINE statement) - * \return index of the new entry in the parameter list - */ -static GLuint -add_parameter(struct parse_state *parseState, - const char *name, const GLfloat values[4], GLboolean constant) -{ - const GLuint n = parseState->numParameters; - - parseState->parameters = _mesa_realloc(parseState->parameters, - n * sizeof(struct program_parameter), - (n + 1) * sizeof(struct program_parameter)); - parseState->numParameters = n + 1; - parseState->parameters[n].Name = _mesa_strdup(name); - COPY_4V(parseState->parameters[n].Values, values); - parseState->parameters[n].Constant = constant; - return n; -} - - -/** - * Add a new unnamed constant to the parameter lists. - * \param parseState parsing state - * \param values four float values - * \return index of the new parameter. - */ -static GLuint -add_unnamed_constant(struct parse_state *parseState, const GLfloat values[4]) -{ - /* generate a new dummy name */ - static GLuint n = 0; - char name[20]; - _mesa_sprintf(name, "constant%d", n); - n++; - /* store it */ - return add_parameter(parseState, name, values, GL_TRUE); -} - - -static const GLfloat * -lookup_parameter(struct parse_state *parseState, const char *name) -{ - GLuint i; - for (i = 0; i < parseState->numParameters; i++) { - if (_mesa_strcmp(parseState->parameters[i].Name, name) == 0) - return parseState->parameters[i].Values; - } - return NULL; -} - - -static const GLint -lookup_parameter_index(struct parse_state *parseState, const char *name) -{ - GLuint i; - for (i = 0; i < parseState->numParameters; i++) { - if (_mesa_strcmp(parseState->parameters[i].Name, name) == 0) - return i; - } - return -1; -} - /* * Called whenever we find an error during parsing. @@ -532,7 +466,8 @@ Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) const GLfloat *constant; if (!Parse_Identifier(parseState, ident)) RETURN_ERROR1("Expected an identifier"); - constant = lookup_parameter(parseState, (const char *) ident); + constant = _mesa_lookup_parameter_value(parseState->parameters, + -1, (const char *) ident); /* XXX Check that it's a constant and not a parameter */ if (!constant) { RETURN_ERROR1("Undefined symbol"); @@ -1078,7 +1013,8 @@ Parse_VectorSrc(struct parse_state *parseState, GLint paramIndex; if (!Parse_Identifier(parseState, ident)) RETURN_ERROR; - paramIndex = lookup_parameter_index(parseState, (const char *) ident); + paramIndex = _mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) ident); if (paramIndex < 0) { RETURN_ERROR2("Undefined constant or parameter: ", ident); } @@ -1091,7 +1027,7 @@ Parse_VectorSrc(struct parse_state *parseState, GLuint paramIndex; if (!Parse_ScalarConstant(parseState, values)) RETURN_ERROR; - paramIndex = add_unnamed_constant(parseState, values); + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } @@ -1102,7 +1038,7 @@ Parse_VectorSrc(struct parse_state *parseState, (void) Parse_String(parseState, "{"); if (!Parse_VectorConstant(parseState, values)) RETURN_ERROR; - paramIndex = add_unnamed_constant(parseState, values); + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } @@ -1188,7 +1124,7 @@ Parse_ScalarSrcReg(struct parse_state *parseState, (void) Parse_String(parseState, "{"); if (!Parse_VectorConstant(parseState, values)) RETURN_ERROR; - paramIndex = add_unnamed_constant(parseState, values); + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } @@ -1198,7 +1134,7 @@ Parse_ScalarSrcReg(struct parse_state *parseState, GLuint paramIndex; if (!Parse_ScalarConstant(parseState, values)) RETURN_ERROR; - paramIndex = add_unnamed_constant(parseState, values); + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); srcReg->Index = paramIndex; srcReg->File = PROGRAM_NAMED_PARAM; needSuffix = GL_FALSE; @@ -1278,10 +1214,12 @@ Parse_InstructionSequence(struct parse_state *parseState, RETURN_ERROR; if (!Parse_String(parseState, ";")) RETURN_ERROR1("Expected ;"); - if (lookup_parameter(parseState, (const char *) id)) { + if (_mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) id) >= 0) { RETURN_ERROR2(id, "already defined"); } - add_parameter(parseState, (const char *) id, value, GL_TRUE); + _mesa_add_named_parameter(parseState->parameters, + (const char *) id, value); } else if (Parse_String(parseState, "DECLARE")) { GLubyte id[100]; @@ -1295,10 +1233,12 @@ Parse_InstructionSequence(struct parse_state *parseState, } if (!Parse_String(parseState, ";")) RETURN_ERROR1("Expected ;"); - if (lookup_parameter(parseState, (const char *) id)) { + if (_mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) id) >= 0) { RETURN_ERROR2(id, "already declared"); } - add_parameter(parseState, (const char *) id, value, GL_FALSE); + _mesa_add_named_parameter(parseState->parameters, + (const char *) id, value); } else if (Parse_String(parseState, "END")) { inst->Opcode = FP_OPCODE_END; @@ -1461,6 +1401,7 @@ _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget, parseState.program = program; parseState.numInst = 0; parseState.curLine = programString; + parseState.parameters = _mesa_new_parameter_list(); /* Reset error state */ _mesa_set_program_error(ctx, -1, NULL); @@ -1530,24 +1471,8 @@ _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget, program->TexturesUsed[u] = parseState.texturesUsed[u]; /* save program parameters */ - if (program->Parameters) { - GLuint i; - for (i = 0; i < program->NumParameters; i++) - _mesa_free((void *) program->Parameters[i].Name); - _mesa_free(program->Parameters); - } - program->NumParameters = parseState.numParameters; program->Parameters = parseState.parameters; - /* free program constants */ - if (parseState.constants) { - GLuint i; - for (i = 0; i < parseState.numConstants; i++) - _mesa_free((void *) parseState.constants[i].Name); - _mesa_free(parseState.constants); - } - - /* allocate registers for declared program parameters */ #if 00 _mesa_assign_program_registers(&(program->SymbolTable)); @@ -1583,15 +1508,17 @@ PrintSrcReg(const struct fragment_program *program, _mesa_printf("-"); } if (src->File == PROGRAM_NAMED_PARAM) { - if (program->Parameters[src->Index].Constant) { + if (program->Parameters->Parameters[src->Index].Type == CONSTANT) { printf("{%g, %g, %g, %g}", - program->Parameters[src->Index].Values[0], - program->Parameters[src->Index].Values[1], - program->Parameters[src->Index].Values[2], - program->Parameters[src->Index].Values[3]); + program->Parameters->Parameters[src->Index].Values[0], + program->Parameters->Parameters[src->Index].Values[1], + program->Parameters->Parameters[src->Index].Values[2], + program->Parameters->Parameters[src->Index].Values[3]); } else { - printf("%s", program->Parameters[src->Index].Name); + ASSERT(program->Parameters->Parameters[src->Index].Type + == NAMED_PARAMETER); + printf("%s", program->Parameters->Parameters[src->Index].Name); } } else if (src->File == PROGRAM_OUTPUT) { diff --git a/src/mesa/main/nvfragprog.h b/src/mesa/main/nvfragprog.h index 33b219c4ce1..cf5253b2457 100644 --- a/src/mesa/main/nvfragprog.h +++ b/src/mesa/main/nvfragprog.h @@ -25,6 +25,8 @@ /* Private fragment program types and constants only used by files * related to fragment programs. + * + * XXX TO-DO: Rename this file "fragprog.h" since it's not NV-specific. */ diff --git a/src/mesa/main/nvprogram.c b/src/mesa/main/nvprogram.c index 61dca5001ac..a4af0eb80a3 100644 --- a/src/mesa/main/nvprogram.c +++ b/src/mesa/main/nvprogram.c @@ -41,294 +41,9 @@ #include "nvvertparse.h" #include "nvvertprog.h" #include "nvprogram.h" +#include "program.h" -/** - * Set the vertex/fragment program error state (position and error string). - * This is generally called from within the parsers. - */ -void -_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string) -{ - ctx->Program.ErrorPos = pos; - _mesa_free((void *) ctx->Program.ErrorString); - if (!string) - string = ""; - ctx->Program.ErrorString = _mesa_strdup(string); -} - - -/** - * Find the line number and column for 'pos' within 'string'. - * Return a copy of the line which contains 'pos'. Free the line with - * _mesa_free(). - * \param string the program string - * \param pos the position within the string - * \param line returns the line number corresponding to 'pos'. - * \param col returns the column number corresponding to 'pos'. - * \return copy of the line containing 'pos'. - */ -const GLubyte * -_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, - GLint *line, GLint *col) -{ - const GLubyte *lineStart = string; - const GLubyte *p = string; - GLubyte *s; - int len; - - *line = 1; - - while (p != pos) { - if (*p == (GLubyte) '\n') { - (*line)++; - lineStart = p + 1; - } - p++; - } - - *col = (pos - lineStart) + 1; - - /* return copy of this line */ - while (*p != 0 && *p != '\n') - p++; - len = p - lineStart; - s = (GLubyte *) _mesa_malloc(len + 1); - _mesa_memcpy(s, lineStart, len); - s[len] = 0; - - return s; -} - - - -/** - * Allocate and initialize a new fragment/vertex program object - * \param ctx context - * \param id program id/number - * \param target program target/type - * \return pointer to new program object - */ -struct program * -_mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id) -{ - struct program *prog; - - if (target == GL_VERTEX_PROGRAM_NV - || target == GL_VERTEX_PROGRAM_ARB) { - struct vertex_program *vprog = CALLOC_STRUCT(vertex_program); - if (!vprog) { - return NULL; - } - prog = &(vprog->Base); - } - else if (target == GL_FRAGMENT_PROGRAM_NV - || target == GL_FRAGMENT_PROGRAM_ARB) { - struct fragment_program *fprog = CALLOC_STRUCT(fragment_program); - if (!fprog) { - return NULL; - } - prog = &(fprog->Base); - } - else { - _mesa_problem(ctx, "bad target in _mesa_alloc_program"); - return NULL; - } - prog->Id = id; - prog->Target = target; - prog->Resident = GL_TRUE; - prog->RefCount = 1; - return prog; -} - - -/** - * Delete a program and remove it from the hash table, ignoring the - * reference count. - * \note Called from the GL API dispatcher. - */ -void -_mesa_delete_program(GLcontext *ctx, struct program *prog) -{ - ASSERT(prog); - - if (prog->String) - _mesa_free(prog->String); - if (prog->Target == GL_VERTEX_PROGRAM_NV || - prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { - struct vertex_program *vprog = (struct vertex_program *) prog; - if (vprog->Instructions) - _mesa_free(vprog->Instructions); - } - else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) { - struct fragment_program *fprog = (struct fragment_program *) prog; - if (fprog->Instructions) - _mesa_free(fprog->Instructions); - if (fprog->Parameters) { - GLuint i; - for (i = 0; i < fprog->NumParameters; i++) { - _mesa_free((void *) fprog->Parameters[i].Name); - } - _mesa_free(fprog->Parameters); - } - } - _mesa_free(prog); -} - - -/** - * Bind a program (make it current) - * \note Called from the GL API dispatcher by both glBindProgramNV - * and glBindProgramARB. - */ -void -_mesa_BindProgramNV(GLenum target, GLuint id) -{ - struct program *prog; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if ((target == GL_VERTEX_PROGRAM_NV - && ctx->Extensions.NV_vertex_program) || - (target == GL_VERTEX_PROGRAM_ARB - && ctx->Extensions.ARB_vertex_program)) { - if (ctx->VertexProgram.Current && - ctx->VertexProgram.Current->Base.Id == id) - return; - /* decrement refcount on previously bound vertex program */ - if (ctx->VertexProgram.Current) { - ctx->VertexProgram.Current->Base.RefCount--; - /* and delete if refcount goes below one */ - if (ctx->VertexProgram.Current->Base.RefCount <= 0) { - _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base)); - _mesa_HashRemove(ctx->Shared->Programs, id); - } - } - } - else if ((target == GL_FRAGMENT_PROGRAM_NV - && ctx->Extensions.NV_fragment_program) || - (target == GL_FRAGMENT_PROGRAM_ARB - && ctx->Extensions.ARB_fragment_program)) { - if (ctx->FragmentProgram.Current && - ctx->FragmentProgram.Current->Base.Id == id) - return; - /* decrement refcount on previously bound fragment program */ - if (ctx->FragmentProgram.Current) { - ctx->FragmentProgram.Current->Base.RefCount--; - /* and delete if refcount goes below one */ - if (ctx->FragmentProgram.Current->Base.RefCount <= 0) { - _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base)); - _mesa_HashRemove(ctx->Shared->Programs, id); - } - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); - return; - } - - /* NOTE: binding to a non-existant program is not an error. - * That's supposed to be caught in glBegin. - */ - if (id == 0) { - /* default program */ - prog = NULL; - if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) - prog = ctx->Shared->DefaultVertexProgram; - else - prog = ctx->Shared->DefaultFragmentProgram; - } - else { - prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); - if (prog) { - if (prog->Target == 0) { - /* prog was allocated with glGenProgramsNV */ - prog->Target = target; - } - else if (prog->Target != target) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindProgramNV/ARB(target mismatch)"); - return; - } - } - else { - /* allocate a new program now */ - prog = _mesa_alloc_program(ctx, target, id); - if (!prog) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); - return; - } - prog->Id = id; - prog->Target = target; - prog->Resident = GL_TRUE; - prog->RefCount = 1; - _mesa_HashInsert(ctx->Shared->Programs, id, prog); - } - } - - /* bind now */ - if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) { - ctx->VertexProgram.Current = (struct vertex_program *) prog; - } - else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) { - ctx->FragmentProgram.Current = (struct fragment_program *) prog; - } - - if (prog) - prog->RefCount++; -} - - -/** - * Delete a list of programs. - * \note Not compiled into display lists. - * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. - */ -void -_mesa_DeleteProgramsNV(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, "glDeleteProgramsNV" ); - return; - } - - for (i = 0; i < n; i++) { - if (ids[i] != 0) { - struct program *prog = (struct program *) - _mesa_HashLookup(ctx->Shared->Programs, ids[i]); - if (prog) { - if (prog->Target == GL_VERTEX_PROGRAM_NV || - prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { - if (ctx->VertexProgram.Current && - ctx->VertexProgram.Current->Base.Id == ids[i]) { - /* unbind this currently bound program */ - _mesa_BindProgramNV(prog->Target, 0); - } - } - else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) { - if (ctx->FragmentProgram.Current && - ctx->FragmentProgram.Current->Base.Id == ids[i]) { - /* unbind this currently bound program */ - _mesa_BindProgramNV(prog->Target, 0); - } - } - else { - _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); - return; - } - prog->RefCount--; - if (prog->RefCount <= 0) { - _mesa_delete_program(ctx, prog); - } - } - } - } -} - /** * Execute a vertex state program. @@ -361,49 +76,6 @@ _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) } -/** - * Generate a list of new program identifiers. - * \note Not compiled into display lists. - * \note Called by both glGenProgramsNV and glGenProgramsARB. - */ -void -_mesa_GenProgramsNV(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); - - for (i = 0; i < (GLuint) n; i++) { - const int bytes = MAX2(sizeof(struct vertex_program), - sizeof(struct fragment_program)); - struct program *prog = (struct program *) _mesa_calloc(bytes); - if (!prog) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms"); - return; - } - prog->RefCount = 1; - prog->Id = first + i; - _mesa_HashInsert(ctx->Shared->Programs, first + i, prog); - } - - /* Return the program names */ - for (i = 0; i < (GLuint) n; i++) { - ids[i] = first + i; - } -} - - /** * Determine if a set of programs is resident in hardware. * \note Not compiled into display lists. @@ -816,30 +488,6 @@ _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer) } -/** - * Determine if id names a 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 -_mesa_IsProgramNV(GLuint id) -{ - struct program *prog; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - if (id == 0) - return GL_FALSE; - - prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); - if (prog && prog->Target) - return GL_TRUE; - else - return GL_FALSE; -} - /** * Load/parse/compile a program. @@ -1101,7 +749,8 @@ _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, { struct program *prog; struct fragment_program *fragProg; - GLuint i; + GLfloat *v; + GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1117,17 +766,13 @@ _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, } fragProg = (struct fragment_program *) prog; - for (i = 0; i < fragProg->NumParameters; i++) { - if (!_mesa_strncmp(fragProg->Parameters[i].Name, - (const char *) name, len) && - fragProg->Parameters[i].Name[len] == 0) { - ASSERT(!fragProg->Parameters[i].Constant); - fragProg->Parameters[i].Values[0] = x; - fragProg->Parameters[i].Values[1] = y; - fragProg->Parameters[i].Values[2] = z; - fragProg->Parameters[i].Values[3] = w; - return; - } + v = _mesa_lookup_parameter_value(fragProg->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"); @@ -1167,7 +812,8 @@ _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, { struct program *prog; struct fragment_program *fragProg; - GLuint i; + const GLfloat *v; + GET_CURRENT_CONTEXT(ctx); if (!ctx->_CurrentProgram) @@ -1185,17 +831,13 @@ _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, } fragProg = (struct fragment_program *) prog; - for (i = 0; i < fragProg->NumParameters; i++) { - if (!_mesa_strncmp(fragProg->Parameters[i].Name, - (const char *) name, len) && - fragProg->Parameters[i].Name[len] == 0) { - ASSERT(!fragProg->Parameters[i].Constant); - params[0] = fragProg->Parameters[i].Values[0]; - params[1] = fragProg->Parameters[i].Values[1]; - params[2] = fragProg->Parameters[i].Values[2]; - params[3] = fragProg->Parameters[i].Values[3]; - return; - } + v = _mesa_lookup_parameter_value(fragProg->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"); diff --git a/src/mesa/main/nvprogram.h b/src/mesa/main/nvprogram.h index c9b8a838d94..f505a84ab8c 100644 --- a/src/mesa/main/nvprogram.h +++ b/src/mesa/main/nvprogram.h @@ -30,36 +30,9 @@ #define NVPROGRAM_H -/** Internal functions **/ -extern void -_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string); - -extern const GLubyte * -_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, - GLint *line, GLint *col); - -extern struct program * -_mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id); - -extern void -_mesa_delete_program(GLcontext *ctx, struct program *prog); - - - -/** API functions **/ - -extern void -_mesa_BindProgramNV(GLenum target, GLuint id); - -extern void -_mesa_DeleteProgramsNV(GLsizei n, const GLuint *ids); - extern void _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params); -extern void -_mesa_GenProgramsNV(GLsizei n, GLuint *ids); - extern GLboolean _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences); @@ -93,9 +66,6 @@ _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params); extern void _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer); -extern GLboolean -_mesa_IsProgramNV(GLuint id); - extern void _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program); @@ -145,32 +115,5 @@ extern void _mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#if 0 -extern void -_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, - GLfloat x, GLfloat y, GLfloat z, GLfloat w); - -extern void -_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, - const GLfloat *params); - -extern void -_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, - GLdouble x, GLdouble y, - GLdouble z, GLdouble w); - -extern void -_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, - const GLdouble *params); - -extern void -_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, - GLfloat *params); - -extern void -_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, - GLdouble *params); -#endif - #endif diff --git a/src/mesa/main/nvvertparse.c b/src/mesa/main/nvvertparse.c index fd99a261f0b..50316b3692f 100644 --- a/src/mesa/main/nvvertparse.c +++ b/src/mesa/main/nvvertparse.c @@ -38,6 +38,8 @@ #include "nvprogram.h" #include "nvvertparse.h" #include "nvvertprog.h" +#include "program.h" + /** * Current parsing state. This structure is passed among the parsing diff --git a/src/mesa/main/nvvertprog.h b/src/mesa/main/nvvertprog.h index 1011fc5ad2d..0dbee780dfd 100644 --- a/src/mesa/main/nvvertprog.h +++ b/src/mesa/main/nvvertprog.h @@ -25,6 +25,8 @@ /* Private vertex program types and constants only used by files * related to vertex programs. + * + * XXX TO-DO: Rename this file "vertprog.h" since it's not NV-specific. */ diff --git a/src/mesa/main/program.c b/src/mesa/main/program.c new file mode 100644 index 00000000000..07ab420bcf7 --- /dev/null +++ b/src/mesa/main/program.c @@ -0,0 +1,927 @@ +/* + * 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. + */ + +/** + * \file program.c + * Vertex and fragment program support functions. + * \author Brian Paul + */ + + +#include "glheader.h" +#include "context.h" +#include "hash.h" +#include "imports.h" +#include "macros.h" +#include "mtypes.h" +#include "program.h" + + +/**********************************************************************/ +/* Utility functions */ +/**********************************************************************/ + + +/** + * Init context's program state + */ +void +_mesa_init_program(GLcontext *ctx) +{ + GLuint i; + + ctx->Program.ErrorPos = -1; + ctx->Program.ErrorString = _mesa_strdup(""); + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + ctx->VertexProgram.Enabled = GL_FALSE; + ctx->VertexProgram.PointSizeEnabled = GL_FALSE; + ctx->VertexProgram.TwoSideEnabled = GL_FALSE; + ctx->VertexProgram.Current = NULL; + ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram; + assert(ctx->VertexProgram.Current); + ctx->VertexProgram.Current->Base.RefCount++; + for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { + ctx->VertexProgram.TrackMatrix[i] = GL_NONE; + ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; + } +#endif + +#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program + ctx->FragmentProgram.Enabled = GL_FALSE; + ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram; + assert(ctx->FragmentProgram.Current); + ctx->FragmentProgram.Current->Base.RefCount++; +#endif +} + + +/** + * Set the vertex/fragment program error state (position and error string). + * This is generally called from within the parsers. + */ +void +_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string) +{ + ctx->Program.ErrorPos = pos; + _mesa_free((void *) ctx->Program.ErrorString); + if (!string) + string = ""; + ctx->Program.ErrorString = _mesa_strdup(string); +} + + +/** + * Find the line number and column for 'pos' within 'string'. + * Return a copy of the line which contains 'pos'. Free the line with + * _mesa_free(). + * \param string the program string + * \param pos the position within the string + * \param line returns the line number corresponding to 'pos'. + * \param col returns the column number corresponding to 'pos'. + * \return copy of the line containing 'pos'. + */ +const GLubyte * +_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, + GLint *line, GLint *col) +{ + const GLubyte *lineStart = string; + const GLubyte *p = string; + GLubyte *s; + int len; + + *line = 1; + + while (p != pos) { + if (*p == (GLubyte) '\n') { + (*line)++; + lineStart = p + 1; + } + p++; + } + + *col = (pos - lineStart) + 1; + + /* return copy of this line */ + while (*p != 0 && *p != '\n') + p++; + len = p - lineStart; + s = (GLubyte *) _mesa_malloc(len + 1); + _mesa_memcpy(s, lineStart, len); + s[len] = 0; + + return s; +} + + + +/** + * Allocate and initialize a new fragment/vertex program object + * \param ctx context + * \param id program id/number + * \param target program target/type + * \return pointer to new program object + */ +struct program * +_mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id) +{ + struct program *prog; + + if (target == GL_VERTEX_PROGRAM_NV + || target == GL_VERTEX_PROGRAM_ARB) { + struct vertex_program *vprog = CALLOC_STRUCT(vertex_program); + if (!vprog) { + return NULL; + } + prog = &(vprog->Base); + } + else if (target == GL_FRAGMENT_PROGRAM_NV + || target == GL_FRAGMENT_PROGRAM_ARB) { + struct fragment_program *fprog = CALLOC_STRUCT(fragment_program); + if (!fprog) { + return NULL; + } + prog = &(fprog->Base); + } + else { + _mesa_problem(ctx, "bad target in _mesa_alloc_program"); + return NULL; + } + prog->Id = id; + prog->Target = target; + prog->Resident = GL_TRUE; + prog->RefCount = 1; + return prog; +} + + +/** + * Delete a program and remove it from the hash table, ignoring the + * reference count. + * \note Called from the GL API dispatcher. + */ +void +_mesa_delete_program(GLcontext *ctx, struct program *prog) +{ + ASSERT(prog); + + if (prog->String) + _mesa_free(prog->String); + if (prog->Target == GL_VERTEX_PROGRAM_NV || + prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { + struct vertex_program *vprog = (struct vertex_program *) prog; + if (vprog->Instructions) + _mesa_free(vprog->Instructions); + } + else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) { + struct fragment_program *fprog = (struct fragment_program *) prog; + if (fprog->Instructions) + _mesa_free(fprog->Instructions); + if (fprog->Parameters) { + _mesa_free_parameter_list(fprog->Parameters); + } + } + _mesa_free(prog); +} + + + +/**********************************************************************/ +/* Program parameter functions */ +/**********************************************************************/ + +struct program_parameter_list * +_mesa_new_parameter_list(void) +{ + return (struct program_parameter_list *) + _mesa_calloc(sizeof(struct program_parameter_list)); +} + + +/** + * Free a parameter list and all its parameters + */ +void +_mesa_free_parameter_list(struct program_parameter_list *paramList) +{ + _mesa_free_parameters(paramList); + _mesa_free(paramList); +} + + +/** + * Free all the parameters in the given list, but don't free the + * paramList structure itself. + */ +void +_mesa_free_parameters(struct program_parameter_list *paramList) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + _mesa_free((void *) paramList->Parameters[i].Name); + } + _mesa_free(paramList->Parameters); + paramList->NumParameters = 0; + paramList->Parameters = NULL; +} + + +/** + * Helper function used by the functions below. + */ +static GLint +add_parameter(struct program_parameter_list *paramList, + const char *name, const GLfloat values[4], + enum parameter_type type) +{ + const GLuint n = paramList->NumParameters; + + paramList->Parameters = _mesa_realloc(paramList->Parameters, + n * sizeof(struct program_parameter), + (n + 1) * sizeof(struct program_parameter)); + if (!paramList->Parameters) { + /* out of memory */ + paramList->NumParameters = 0; + return -1; + } + else { + paramList->NumParameters = n + 1; + paramList->Parameters[n].Name = _mesa_strdup(name); + paramList->Parameters[n].Type = type; + if (values) + COPY_4V(paramList->Parameters[n].Values, values); + return (GLint) n; + } +} + + +/** + * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement) + * \return index of the new entry in the parameter list + */ +GLint +_mesa_add_named_parameter(struct program_parameter_list *paramList, + const char *name, const GLfloat values[4]) +{ + return add_parameter(paramList, name, values, NAMED_PARAMETER); +} + + +/** + * Add a new unnamed constant to the parameter list. + * \param paramList - the parameter list + * \param values - four float values + * \return index of the new parameter. + */ +GLint +_mesa_add_named_constant(struct program_parameter_list *paramList, + const char *name, const GLfloat values[4]) +{ + return add_parameter(paramList, name, values, CONSTANT); +} + + +/** + * Add a new unnamed constant to the parameter list. + * \param paramList - the parameter list + * \param values - four float values + * \return index of the new parameter. + */ +GLint +_mesa_add_unnamed_constant(struct program_parameter_list *paramList, + const GLfloat values[4]) +{ + /* generate a new dummy name */ + static GLuint n = 0; + char name[20]; + _mesa_sprintf(name, "constant%d", n); + n++; + /* store it */ + return add_parameter(paramList, name, values, CONSTANT); +} + + +/** + * Add a new state reference to the parameter list. + * \param paramList - the parameter list + * \param values - four float values + * \return index of the new parameter. + */ +GLint +_mesa_add_state_reference(struct program_parameter_list *paramList, + const char *stateString) +{ + /* XXX Should we parse here and produce the parameter's + * list of STATE_* tokens here, or in the parser? + */ + return add_parameter(paramList, stateString, NULL, STATE); +} + + +/** + * Lookup a parameter value by name in the given parameter list. + * \return pointer to the float[4] values. + */ +GLfloat * +_mesa_lookup_parameter_value(struct program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLuint i; + + if (nameLen == -1) { + /* name is null-terminated */ + for (i = 0; i < paramList->NumParameters; i++) { + if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0) + return paramList->Parameters[i].Values; + } + } + else { + /* name is not null-terminated, use nameLen */ + for (i = 0; i < paramList->NumParameters; i++) { + if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 + && _mesa_strlen(paramList->Parameters[i].Name) == nameLen) + return paramList->Parameters[i].Values; + } + } + return NULL; +} + + +/** + * Lookup a parameter index by name in the given parameter list. + * \return index of parameter in the list. + */ +GLint +_mesa_lookup_parameter_index(struct program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLint i; + + if (nameLen == -1) { + /* name is null-terminated */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0) + return i; + } + } + else { + /* name is not null-terminated, use nameLen */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 + && _mesa_strlen(paramList->Parameters[i].Name) == nameLen) + return i; + } + } + return -1; +} + + +/** + * Use the list of tokens in the state[] array to find global GL state + * and return it in . Usually, four values are returned in + * but matrix queries may return as many as 16 values. + * This function is used for ARB vertex/fragment programs. + * The program parser will produce the state[] values. + */ +static void +_mesa_fetch_state(GLcontext *ctx, const enum state_index state[], + GLfloat *value) +{ + switch (state[0]) { + case STATE_MATERIAL: + { + /* state[1] is either 0=front or 1=back side */ + const GLuint face = (GLuint) state[1]; + /* state[2] is the material attribute */ + switch (state[2]) { + case STATE_AMBIENT: + if (face == 0) + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]); + else + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]); + return; + case STATE_DIFFUSE: + if (face == 0) + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]); + else + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]); + return; + case STATE_SPECULAR: + if (face == 0) + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]); + else + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]); + return; + case STATE_EMISSION: + if (face == 0) + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]); + else + COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]); + return; + case STATE_SHININESS: + if (face == 0) + value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0]; + else + value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0]; + value[1] = 0.0F; + value[2] = 0.0F; + value[3] = 1.0F; + return; + default: + _mesa_problem(ctx, "Invalid material state in fetch_state"); + return; + } + }; + return; + case STATE_LIGHT: + { + /* state[1] is the light number */ + const GLuint ln = (GLuint) state[1]; + /* state[2] is the light attribute */ + switch (state[2]) { + case STATE_AMBIENT: + COPY_4V(value, ctx->Light.Light[ln].Ambient); + return; + case STATE_DIFFUSE: + COPY_4V(value, ctx->Light.Light[ln].Diffuse); + return; + case STATE_SPECULAR: + COPY_4V(value, ctx->Light.Light[ln].Specular); + return; + case STATE_POSITION: + COPY_4V(value, ctx->Light.Light[ln].EyePosition); + return; + case STATE_ATTENUATION: + value[0] = ctx->Light.Light[ln].ConstantAttenuation; + value[1] = ctx->Light.Light[ln].LinearAttenuation; + value[2] = ctx->Light.Light[ln].QuadraticAttenuation; + value[3] = ctx->Light.Light[ln].SpotExponent; + return; + case STATE_SPOT_DIRECTION: + COPY_4V(value, ctx->Light.Light[ln].EyeDirection); + return; + default: + _mesa_problem(ctx, "Invalid light state in fetch_state"); + return; + } + } + return; + case STATE_LIGHTMODEL_AMBIENT: + COPY_4V(value, ctx->Light.Model.Ambient); + return; + case STATE_LIGHTMODEL_SCENECOLOR: + if (state[1] == 0) { + /* front */ + GLint i; + for (i = 0; i < 4; i++) { + value[i] = ctx->Light.Model.Ambient[i] + * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i] + + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i]; + } + } + else { + /* back */ + GLint i; + for (i = 0; i < 4; i++) { + value[i] = ctx->Light.Model.Ambient[i] + * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i] + + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i]; + } + } + return; + case STATE_LIGHTPROD: + { + const GLuint ln = (GLuint) state[1]; + const GLuint face = (GLuint) state[2]; + GLint i; + ASSERT(face == 0 || face == 1); + switch (state[3]) { + case STATE_AMBIENT: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Ambient[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; + return; + case STATE_DIFFUSE: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Diffuse[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; + return; + case STATE_SPECULAR: + for (i = 0; i < 3; i++) { + value[i] = ctx->Light.Light[ln].Specular[i] * + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i]; + } + /* [3] = material alpha */ + value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; + return; + default: + _mesa_problem(ctx, "Invalid lightprod state in fetch_state"); + return; + } + } + return; + case STATE_TEXGEN: + { + /* state[1] is the texture unit */ + const GLuint unit = (GLuint) state[1]; + /* state[2] is the texgen attribute */ + switch (state[2]) { + case STATE_TEXGEN_EYE_S: + COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS); + return; + case STATE_TEXGEN_EYE_T: + COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT); + return; + case STATE_TEXGEN_EYE_R: + COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR); + return; + case STATE_TEXGEN_EYE_Q: + COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ); + return; + case STATE_TEXGEN_OBJECT_S: + COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS); + return; + case STATE_TEXGEN_OBJECT_T: + COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT); + return; + case STATE_TEXGEN_OBJECT_R: + COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR); + return; + case STATE_TEXGEN_OBJECT_Q: + COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ); + return; + default: + _mesa_problem(ctx, "Invalid texgen state in fetch_state"); + return; + } + } + return; + case STATE_FOG_COLOR: + COPY_4V(value, ctx->Fog.Color); + return; + case STATE_FOG_PARAMS: + value[0] = ctx->Fog.Density; + value[1] = ctx->Fog.Start; + value[2] = ctx->Fog.End; + value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.End); + return; + case STATE_CLIPPLANE: + { + const GLuint plane = (GLuint) state[1]; + COPY_4V(value, ctx->Transform.EyeUserPlane[plane]); + } + return; + case STATE_POINT_SIZE: + value[0] = ctx->Point.Size; + value[1] = ctx->Point.MinSize; + value[2] = ctx->Point.MaxSize; + value[3] = ctx->Point.Threshold; + return; + case STATE_POINT_ATTENUATION: + value[0] = ctx->Point.Params[0]; + value[1] = ctx->Point.Params[1]; + value[2] = ctx->Point.Params[2]; + value[3] = 1.0F; + return; + case STATE_MATRIX: + { + /* state[1] = modelview, projection, texture, etc. */ + /* state[2] = which texture matrix or program matrix */ + /* state[3] = first column to fetch */ + /* state[4] = last column to fetch */ + /* state[5] = transpose, inverse or invtrans */ + + const GLmatrix *matrix; + const enum state_index mat = state[1]; + const GLuint index = (GLuint) state[2]; + const GLuint first = (GLuint) state[3]; + const GLuint last = (GLuint) state[4]; + const enum state_index modifier = state[5]; + const GLfloat *m; + GLuint row, i; + if (mat == STATE_MODELVIEW) { + matrix = ctx->ModelviewMatrixStack.Top; + } + else if (mat == STATE_PROJECTION) { + matrix = ctx->ProjectionMatrixStack.Top; + } + else if (mat == STATE_MVP) { + matrix = &ctx->_ModelProjectMatrix; + } + else if (mat == STATE_TEXTURE) { + matrix = ctx->TextureMatrixStack[index].Top; + } + else if (mat == STATE_PROGRAM) { + matrix = ctx->ProgramMatrixStack[index].Top; + } + else { + _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()"); + return; + } + if (modifier == STATE_MATRIX_INVERSE || + modifier == STATE_MATRIX_INVTRANS) { + /* XXX be sure inverse is up to date */ + m = matrix->inv; + } + else { + m = matrix->m; + } + if (modifier == STATE_MATRIX_TRANSPOSE || + modifier == STATE_MATRIX_INVTRANS) { + for (i = 0, row = first; row <= last; row++) { + value[i++] = m[row * 4 + 0]; + value[i++] = m[row * 4 + 1]; + value[i++] = m[row * 4 + 2]; + value[i++] = m[row * 4 + 3]; + } + } + else { + for (i = 0, row = first; row <= last; row++) { + value[i++] = m[row + 0]; + value[i++] = m[row + 4]; + value[i++] = m[row + 8]; + value[i++] = m[row + 12]; + } + } + } + return; + default: + _mesa_problem(ctx, "Invalid state in fetch_state"); + return; + } +} + + +/** + * Loop over all the parameters in a parameter list. If the parameter + * is a GL state reference, look up the current value of that state + * variable and put it into the parameter's Value[4] array. + * This would be called at glBegin time when using a fragment program. + */ +void +_mesa_load_state_parameters(GLcontext *ctx, + struct program_parameter_list *paramList) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Type == STATE) { + _mesa_fetch_state(ctx, paramList->Parameters[i].StateIndexes, + paramList->Parameters[i].Values); + } + } +} + + + +/**********************************************************************/ +/* API functions */ +/**********************************************************************/ + + +/** + * Bind a program (make it current) + * \note Called from the GL API dispatcher by both glBindProgramNV + * and glBindProgramARB. + */ +void +_mesa_BindProgram(GLenum target, GLuint id) +{ + struct program *prog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if ((target == GL_VERTEX_PROGRAM_NV + && ctx->Extensions.NV_vertex_program) || + (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program)) { + if (ctx->VertexProgram.Current && + ctx->VertexProgram.Current->Base.Id == id) + return; + /* decrement refcount on previously bound vertex program */ + if (ctx->VertexProgram.Current) { + ctx->VertexProgram.Current->Base.RefCount--; + /* and delete if refcount goes below one */ + if (ctx->VertexProgram.Current->Base.RefCount <= 0) { + _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base)); + _mesa_HashRemove(ctx->Shared->Programs, id); + } + } + } + else if ((target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) || + (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program)) { + if (ctx->FragmentProgram.Current && + ctx->FragmentProgram.Current->Base.Id == id) + return; + /* decrement refcount on previously bound fragment program */ + if (ctx->FragmentProgram.Current) { + ctx->FragmentProgram.Current->Base.RefCount--; + /* and delete if refcount goes below one */ + if (ctx->FragmentProgram.Current->Base.RefCount <= 0) { + _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base)); + _mesa_HashRemove(ctx->Shared->Programs, id); + } + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); + return; + } + + /* NOTE: binding to a non-existant program is not an error. + * That's supposed to be caught in glBegin. + */ + if (id == 0) { + /* default program */ + prog = NULL; + if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) + prog = ctx->Shared->DefaultVertexProgram; + else + prog = ctx->Shared->DefaultFragmentProgram; + } + else { + prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); + if (prog) { + if (prog->Target == 0) { + /* prog was allocated with glGenProgramsNV */ + prog->Target = target; + } + else if (prog->Target != target) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindProgramNV/ARB(target mismatch)"); + return; + } + } + else { + /* allocate a new program now */ + prog = _mesa_alloc_program(ctx, target, id); + if (!prog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); + return; + } + prog->Id = id; + prog->Target = target; + prog->Resident = GL_TRUE; + prog->RefCount = 1; + _mesa_HashInsert(ctx->Shared->Programs, id, prog); + } + } + + /* bind now */ + if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) { + ctx->VertexProgram.Current = (struct vertex_program *) prog; + } + else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) { + ctx->FragmentProgram.Current = (struct fragment_program *) prog; + } + + if (prog) + prog->RefCount++; +} + + +/** + * Delete a list of programs. + * \note Not compiled into display lists. + * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. + */ +void +_mesa_DeletePrograms(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, "glDeleteProgramsNV" ); + return; + } + + for (i = 0; i < n; i++) { + if (ids[i] != 0) { + struct program *prog = (struct program *) + _mesa_HashLookup(ctx->Shared->Programs, ids[i]); + if (prog) { + if (prog->Target == GL_VERTEX_PROGRAM_NV || + prog->Target == 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); + } + } + else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) { + if (ctx->FragmentProgram.Current && + ctx->FragmentProgram.Current->Base.Id == ids[i]) { + /* unbind this currently bound program */ + _mesa_BindProgram(prog->Target, 0); + } + } + else { + _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); + return; + } + prog->RefCount--; + if (prog->RefCount <= 0) { + _mesa_delete_program(ctx, prog); + } + } + } + } +} + + +/** + * Generate a list of new program identifiers. + * \note Not compiled into display lists. + * \note Called by both glGenProgramsNV and glGenProgramsARB. + */ +void +_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); + + for (i = 0; i < (GLuint) n; i++) { + const int bytes = MAX2(sizeof(struct vertex_program), + sizeof(struct fragment_program)); + struct program *prog = (struct program *) _mesa_calloc(bytes); + if (!prog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms"); + return; + } + prog->RefCount = 1; + prog->Id = first + i; + _mesa_HashInsert(ctx->Shared->Programs, first + i, prog); + } + + /* Return the program names */ + for (i = 0; i < (GLuint) n; i++) { + ids[i] = first + i; + } +} + + +/** + * Determine if id names a 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 +_mesa_IsProgram(GLuint id) +{ + struct program *prog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (id == 0) + return GL_FALSE; + + prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); + if (prog && prog->Target) + return GL_TRUE; + else + return GL_FALSE; +} diff --git a/src/mesa/main/program.h b/src/mesa/main/program.h new file mode 100644 index 00000000000..02d962c7965 --- /dev/null +++ b/src/mesa/main/program.h @@ -0,0 +1,207 @@ +/* + * 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. + */ + +/** + * \file program.c + * Vertex and fragment program support functions. + * \author Brian Paul + */ + + +#ifndef PROGRAM_H +#define PROGRAM_H + +#include "mtypes.h" + + + +/* + * Internal functions + */ + +extern void +_mesa_init_program(GLcontext *ctx); + +extern void +_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string); + +extern const GLubyte * +_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, + GLint *line, GLint *col); + +extern struct program * +_mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id); + +extern void +_mesa_delete_program(GLcontext *ctx, struct program *prog); + + + +/* + * Used for describing GL state referenced from inside ARB vertex and + * fragment programs. + * A string such as "state.light[0].ambient" gets translated into a + * sequence of tokens such as [ STATE_LIGHT, 0, STATE_AMBIENT ]. + */ +enum state_index { + STATE_MATERIAL, + + STATE_LIGHT, + STATE_LIGHTMODEL_AMBIENT, + STATE_LIGHTMODEL_SCENECOLOR, + STATE_LIGHTPROD, + + STATE_TEXGEN, + + STATE_FOG_COLOR, + STATE_FOG_PARAMS, + + STATE_CLIPPLANE, + + STATE_POINT_SIZE, + STATE_POINT_ATTENUATION, + + STATE_MATRIX, + STATE_MODELVIEW, + STATE_PROJECTION, + STATE_MVP, + STATE_TEXTURE, + STATE_PROGRAM, + STATE_MATRIX_INVERSE, + STATE_MATRIX_TRANSPOSE, + STATE_MATRIX_INVTRANS, + + STATE_AMBIENT, + STATE_DIFFUSE, + STATE_SPECULAR, + STATE_EMISSION, + STATE_SHININESS, + + STATE_POSITION, + STATE_ATTENUATION, + STATE_SPOT_DIRECTION, + + STATE_TEXGEN_EYE_S, + STATE_TEXGEN_EYE_T, + STATE_TEXGEN_EYE_R, + STATE_TEXGEN_EYE_Q, + STATE_TEXGEN_OBJECT_S, + STATE_TEXGEN_OBJECT_T, + STATE_TEXGEN_OBJECT_R, + STATE_TEXGEN_OBJECT_Q +}; + + + +/* + * Named program parameters + * Used for NV_fragment_program "DEFINE"d constants and "DECLARE"d parameters, + * and ARB_fragment_program global state references. For the later, Name + * might be "state.light[0].diffuse", for example. + */ + +enum parameter_type +{ + NAMED_PARAMETER, + CONSTANT, + STATE +}; + + +struct program_parameter +{ + const char *Name; /* Null-terminated */ + enum parameter_type Type; + enum state_index StateIndexes[5]; /* Global state reference */ + GLfloat Values[4]; +}; + + +struct program_parameter_list +{ + GLuint NumParameters; + struct program_parameter *Parameters; +}; + + +/* + * Program parameter functions + */ + +extern struct program_parameter_list * +_mesa_new_parameter_list(void); + +extern void +_mesa_free_parameter_list(struct program_parameter_list *paramList); + +extern void +_mesa_free_parameters(struct program_parameter_list *paramList); + +extern GLint +_mesa_add_named_parameter(struct program_parameter_list *paramList, + const char *name, const GLfloat values[4]); + +extern GLint +_mesa_add_named_constant(struct program_parameter_list *paramList, + const char *name, const GLfloat values[4]); + +extern GLint +_mesa_add_unnamed_constant(struct program_parameter_list *paramList, + const GLfloat values[4]); + +extern GLint +_mesa_add_state_reference(struct program_parameter_list *paramList, + const char *stateString); + +extern GLfloat * +_mesa_lookup_parameter_value(struct program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern GLint +_mesa_lookup_parameter_index(struct program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern void +_mesa_load_state_parameters(GLcontext *ctx, + struct program_parameter_list *paramList); + + +/* + * API functions + */ + +extern void +_mesa_BindProgram(GLenum target, GLuint id); + +extern void +_mesa_DeletePrograms(GLsizei n, const GLuint *ids); + +extern void +_mesa_GenPrograms(GLsizei n, GLuint *ids); + +extern GLboolean +_mesa_IsProgram(GLuint id); + + +#endif /* PROGRAM_H */ diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 7b535193717..2922828d22b 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -75,11 +75,13 @@ #include "texstate.h" #include "mtypes.h" #include "varray.h" -#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program +#if FEATURE_NV_vertex_program #include "nvprogram.h" #endif #if FEATURE_NV_fragment_program #include "nvfragprog.h" +#include "nvprogram.h" +#include "program.h" #endif #include "debug.h" @@ -544,10 +546,10 @@ _mesa_init_exec_table(struct _glapi_table *exec, GLuint tableSize) /* 233. GL_NV_vertex_program */ #if FEATURE_NV_vertex_program - exec->BindProgramNV = _mesa_BindProgramNV; - exec->DeleteProgramsNV = _mesa_DeleteProgramsNV; + exec->BindProgramNV = _mesa_BindProgram; + exec->DeleteProgramsNV = _mesa_DeletePrograms; exec->ExecuteProgramNV = _mesa_ExecuteProgramNV; - exec->GenProgramsNV = _mesa_GenProgramsNV; + exec->GenProgramsNV = _mesa_GenPrograms; exec->AreProgramsResidentNV = _mesa_AreProgramsResidentNV; exec->RequestResidentProgramsNV = _mesa_RequestResidentProgramsNV; exec->GetProgramParameterfvNV = _mesa_GetProgramParameterfvNV; @@ -559,7 +561,7 @@ _mesa_init_exec_table(struct _glapi_table *exec, GLuint tableSize) exec->GetVertexAttribfvNV = _mesa_GetVertexAttribfvNV; exec->GetVertexAttribivNV = _mesa_GetVertexAttribivNV; exec->GetVertexAttribPointervNV = _mesa_GetVertexAttribPointervNV; - exec->IsProgramNV = _mesa_IsProgramNV; + exec->IsProgramNV = _mesa_IsProgram; exec->LoadProgramNV = _mesa_LoadProgramNV; exec->ProgramParameter4dNV = _mesa_ProgramParameter4dNV; exec->ProgramParameter4dvNV = _mesa_ProgramParameter4dvNV;