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.
This commit is contained in:
Brian Paul 2003-08-31 18:52:47 +00:00
parent e38a55ecb2
commit 04a81da03b
18 changed files with 1216 additions and 596 deletions

View File

@ -62,6 +62,7 @@ CORE_SOURCES = \
pixel.c \
points.c \
polygon.c \
program.c \
rastpos.c \
state.c \
stencil.c \

View File

@ -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,

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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] */
};

View File

@ -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) {

View File

@ -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.
*/

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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.
*/

927
src/mesa/main/program.c Normal file
View File

@ -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 <stateString> 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 <value>. Usually, four values are returned in <value>
* 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;
}

207
src/mesa/main/program.h Normal file
View File

@ -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 */

View File

@ -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;