/*
* Mesa 3-D graphics library
- * Version: 6.5
+ * Version: 6.5.2
*
- * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
static const char *
make_state_string(const GLint stateTokens[6]);
+static GLbitfield
+make_state_flags(const GLint state[]);
+
/**********************************************************************/
/* Utility functions */
/* A pointer to this dummy program is put into the hash table when
* glGenPrograms is called.
*/
-struct program _mesa_DummyProgram;
+struct gl_program _mesa_DummyProgram;
/**
ctx->VertexProgram.Enabled = GL_FALSE;
ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
- ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram;
+ ctx->VertexProgram.Current = (struct gl_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++) {
#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
ctx->FragmentProgram.Enabled = GL_FALSE;
- ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram;
+ ctx->FragmentProgram.Current = (struct gl_fragment_program *) ctx->Shared->DefaultFragmentProgram;
assert(ctx->FragmentProgram.Current);
ctx->FragmentProgram.Current->Base.RefCount++;
#endif
+ /* XXX probably move this stuff */
#if FEATURE_ATI_fragment_shader
ctx->ATIFragmentShader.Enabled = GL_FALSE;
ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
assert(ctx->ATIFragmentShader.Current);
- ctx->ATIFragmentShader.Current->Base.RefCount++;
+ ctx->ATIFragmentShader.Current->RefCount++;
#endif
}
void
_mesa_free_program_data(GLcontext *ctx)
{
-#if FEATURE_NV_vertex_program
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
if (ctx->VertexProgram.Current) {
ctx->VertexProgram.Current->Base.RefCount--;
if (ctx->VertexProgram.Current->Base.RefCount <= 0)
ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
}
#endif
-#if FEATURE_NV_fragment_program
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
if (ctx->FragmentProgram.Current) {
ctx->FragmentProgram.Current->Base.RefCount--;
if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
}
#endif
+ /* XXX probably move this stuff */
#if FEATURE_ATI_fragment_shader
if (ctx->ATIFragmentShader.Current) {
- ctx->ATIFragmentShader.Current->Base.RefCount--;
- if (ctx->ATIFragmentShader.Current->Base.RefCount <= 0)
- ctx->Driver.DeleteProgram(ctx, &(ctx->ATIFragmentShader.Current->Base));
+ ctx->ATIFragmentShader.Current->RefCount--;
+ if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
+ _mesa_free(ctx->ATIFragmentShader.Current);
+ }
}
#endif
_mesa_free((void *) ctx->Program.ErrorString);
/**
* Initialize a new vertex/fragment program object.
*/
-static struct program *
-_mesa_init_program_struct( GLcontext *ctx, struct program *prog,
+static struct gl_program *
+_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
GLenum target, GLuint id)
{
(void) ctx;
prog->Target = target;
prog->Resident = GL_TRUE;
prog->RefCount = 1;
+ prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
}
return prog;
/**
* Initialize a new fragment program object.
*/
-struct program *
-_mesa_init_fragment_program( GLcontext *ctx, struct fragment_program *prog,
+struct gl_program *
+_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog,
GLenum target, GLuint id)
{
if (prog)
/**
* Initialize a new vertex program object.
*/
-struct program *
-_mesa_init_vertex_program( GLcontext *ctx, struct vertex_program *prog,
+struct gl_program *
+_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
GLenum target, GLuint id)
{
if (prog)
return NULL;
}
-/**
- * Initialize a new ATI fragment shader object.
- */
-struct program *
-_mesa_init_ati_fragment_shader( GLcontext *ctx,
- struct ati_fragment_shader *prog,
- GLenum target, GLuint id )
-{
- if (prog)
- return _mesa_init_program_struct( ctx, &prog->Base, target, id );
- else
- return NULL;
-}
-
-
/**
* Allocate and initialize a new fragment/vertex program object but
* \param target program target/type
* \return pointer to new program object
*/
-struct program *
+struct gl_program *
_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
{
switch (target) {
case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
- return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program),
- target, id );
+ return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
+ target, id );
case GL_FRAGMENT_PROGRAM_NV:
case GL_FRAGMENT_PROGRAM_ARB:
- return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program),
- target, id );
- case GL_FRAGMENT_SHADER_ATI:
- return _mesa_init_ati_fragment_shader( ctx, CALLOC_STRUCT(ati_fragment_shader),
- target, id );
-
+ return _mesa_init_fragment_program(ctx,
+ CALLOC_STRUCT(gl_fragment_program),
+ target, id );
default:
_mesa_problem(ctx, "bad target in _mesa_new_program");
return NULL;
* by a device driver function.
*/
void
-_mesa_delete_program(GLcontext *ctx, struct program *prog)
+_mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
{
(void) ctx;
ASSERT(prog);
+ if (prog == &_mesa_DummyProgram)
+ return;
+
if (prog->String)
_mesa_free(prog->String);
_mesa_free(prog->Instructions);
}
- if (prog->Parameters)
+ if (prog->Parameters) {
_mesa_free_parameter_list(prog->Parameters);
+ }
- if (prog->Target == GL_FRAGMENT_SHADER_ATI) {
- struct ati_fragment_shader *atifs = (struct ati_fragment_shader *)prog;
- GLuint i;
- for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
- if (atifs->Instructions[i])
- _mesa_free(atifs->Instructions[i]);
- if (atifs->SetupInst[i])
- _mesa_free(atifs->SetupInst[i]);
- }
+ /* XXX this is a little ugly */
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
+ if (vprog->TnlData)
+ _mesa_free(vprog->TnlData);
}
_mesa_free(prog);
}
+/**
+ * Return the gl_program object for a given ID.
+ * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
+ * casts elsewhere.
+ */
+struct gl_program *
+_mesa_lookup_program(GLcontext *ctx, GLuint id)
+{
+ if (id)
+ return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+ else
+ return NULL;
+}
+
/**********************************************************************/
/* Program parameter functions */
/**********************************************************************/
-struct program_parameter_list *
+struct gl_program_parameter_list *
_mesa_new_parameter_list(void)
{
- return (struct program_parameter_list *)
- _mesa_calloc(sizeof(struct program_parameter_list));
+ return (struct gl_program_parameter_list *)
+ _mesa_calloc(sizeof(struct gl_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->Parameters);
- if (paramList->ParameterValues)
- ALIGN_FREE(paramList->ParameterValues);
- _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)
+_mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
{
GLuint i;
for (i = 0; i < paramList->NumParameters; i++) {
if (paramList->Parameters[i].Name)
_mesa_free((void *) paramList->Parameters[i].Name);
}
- paramList->NumParameters = 0;
+ _mesa_free(paramList->Parameters);
+ if (paramList->ParameterValues)
+ _mesa_align_free(paramList->ParameterValues);
+ _mesa_free(paramList);
}
/**
- * Helper function used by the functions below.
+ * Add a new parameter to a parameter list.
+ * \param paramList the list to add the parameter to
+ * \param name the parameter name, will be duplicated/copied!
+ * \param values initial parameter value, 4 GLfloats
+ * \param type type of parameter, such as
* \return index of new parameter in the list, or -1 if error (out of mem)
*/
static GLint
-add_parameter(struct program_parameter_list *paramList,
+add_parameter(struct gl_program_parameter_list *paramList,
const char *name, const GLfloat values[4],
enum register_file type)
{
const GLuint n = paramList->NumParameters;
if (n == paramList->Size) {
- GLfloat (*tmp)[4];
-
- paramList->Size *= 2;
- if (!paramList->Size)
+ /* Need to grow the parameter list array */
+ if (paramList->Size == 0)
paramList->Size = 8;
+ else
+ paramList->Size *= 2;
- paramList->Parameters = (struct program_parameter *)
+ /* realloc arrays */
+ paramList->Parameters = (struct gl_program_parameter *)
_mesa_realloc(paramList->Parameters,
- n * sizeof(struct program_parameter),
- paramList->Size * sizeof(struct program_parameter));
-
- tmp = paramList->ParameterValues;
- paramList->ParameterValues = ALIGN_MALLOC(paramList->Size * 4 * sizeof(GLfloat), 16);
- if (tmp) {
- _mesa_memcpy(paramList->ParameterValues, tmp,
- n * 4 * sizeof(GLfloat));
- ALIGN_FREE(tmp);
- }
+ n * sizeof(struct gl_program_parameter),
+ paramList->Size * sizeof(struct gl_program_parameter));
+
+ paramList->ParameterValues = (GLfloat (*)[4])
+ _mesa_align_realloc(paramList->ParameterValues, /* old buf */
+ n * 4 * sizeof(GLfloat), /* old size */
+ paramList->Size * 4 *sizeof(GLfloat), /* new sz */
+ 16);
}
if (!paramList->Parameters ||
paramList->NumParameters = n + 1;
_mesa_memset(¶mList->Parameters[n], 0,
- sizeof(struct program_parameter));
+ sizeof(struct gl_program_parameter));
paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
paramList->Parameters[n].Type = type;
* \return index of the new entry in the parameter list
*/
GLint
-_mesa_add_named_parameter(struct program_parameter_list *paramList,
+_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
const char *name, const GLfloat values[4])
{
return add_parameter(paramList, name, values, PROGRAM_NAMED_PARAM);
/**
- * 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.
+ * Add a new named constant to the parameter list.
+ * This will be used when the program contains something like this:
+ * PARAM myVals = { 0, 1, 2, 3 };
+ *
+ * \param paramList the parameter list
+ * \param name the name for the constant
+ * \param values four float values
+ * \return index/position of the new parameter in the parameter list
*/
GLint
-_mesa_add_named_constant(struct program_parameter_list *paramList,
- const char *name, const GLfloat values[4])
+_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
+ const char *name, const GLfloat values[4],
+ GLuint size)
{
+#if 0 /* disable this for now -- we need to save the name! */
+ GLuint pos, swizzle;
+ ASSERT(size == 4); /* XXX future feature */
+ /* check if we already have this constant */
+ if (_mesa_lookup_parameter_constant(paramList, values, 4, &pos, &swizzle)) {
+ return pos;
+ }
+#endif
return add_parameter(paramList, name, values, PROGRAM_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.
+ * This will be used when the program contains something like this:
+ * MOV r, { 0, 1, 2, 3 };
+ *
+ * \param paramList the parameter list
+ * \param values four float values
+ * \return index/position of the new parameter in the parameter list.
*/
GLint
-_mesa_add_unnamed_constant(struct program_parameter_list *paramList,
- const GLfloat values[4])
+_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
+ const GLfloat values[4], GLuint size)
{
+ GLuint pos, swizzle;
+ ASSERT(size == 4); /* XXX future feature */
+ /* check if we already have this constant */
+ if (_mesa_lookup_parameter_constant(paramList, values, 4, &pos, &swizzle)) {
+ return pos;
+ }
return add_parameter(paramList, NULL, values, PROGRAM_CONSTANT);
}
/**
* Add a new state reference to the parameter list.
- * \param paramList - the parameter list
- * \param state - an array of 6 state tokens
+ * This will be used when the program contains something like this:
+ * PARAM ambient = state.material.front.ambient;
*
+ * \param paramList the parameter list
+ * \param state an array of 6 state tokens
* \return index of the new parameter.
*/
GLint
-_mesa_add_state_reference(struct program_parameter_list *paramList,
+_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
const GLint *stateTokens)
{
/* XXX we should probably search the current parameter list to see if
index = add_parameter(paramList, name, NULL, PROGRAM_STATE_VAR);
if (index >= 0) {
GLuint i;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++) {
paramList->Parameters[index].StateIndexes[i]
= (enum state_index) stateTokens[i];
+ }
+ paramList->StateFlags |= make_state_flags(stateTokens);
}
+ /* free name string here since we duplicated it in add_parameter() */
+ _mesa_free((void *) name);
+
return index;
}
* \return pointer to the float[4] values.
*/
GLfloat *
-_mesa_lookup_parameter_value(struct program_parameter_list *paramList,
+_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
GLsizei nameLen, const char *name)
{
GLuint i;
/**
- * Lookup a parameter index by name in the given parameter list.
+ * Given a program parameter name, find its position in the list of parameters.
+ * \param paramList the parameter list to search
+ * \param nameLen length of name (in chars).
+ * If length is negative, assume that name is null-terminated.
+ * \param name the name to search for
* \return index of parameter in the list.
*/
GLint
-_mesa_lookup_parameter_index(struct program_parameter_list *paramList,
+_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
GLsizei nameLen, const char *name)
{
GLint i;
}
+/**
+ * Look for a float vector in the given parameter list. The float vector
+ * may be of length 1, 2, 3 or 4.
+ * \param paramList the parameter list to search
+ * \param v the float vector to search for
+ * \param size number of element in v
+ * \param posOut returns the position of the constant, if found
+ * \param swizzleOut returns a swizzle mask describing location of the
+ * vector elements if found
+ * \return GL_TRUE if found, GL_FALSE if not found
+ */
+GLboolean
+_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *paramList,
+ const GLfloat v[], GLsizei vSize,
+ GLuint *posOut, GLuint *swizzleOut)
+{
+ GLuint i;
+
+ assert(vSize >= 1);
+ assert(vSize <= 4);
+
+ if (!paramList)
+ return -1;
+
+ for (i = 0; i < paramList->NumParameters; i++) {
+ if (paramList->Parameters[i].Type == PROGRAM_CONSTANT) {
+ const GLint maxShift = 4 - vSize;
+ GLint shift, j;
+ for (shift = 0; shift <= maxShift; shift++) {
+ GLint matched = 0;
+ GLuint swizzle[4];
+ swizzle[0] = swizzle[1] = swizzle[2] = swizzle[3] = 0;
+ /* XXX we could do out-of-order swizzle matches too, someday */
+ for (j = 0; j < vSize; j++) {
+ assert(shift + j < 4);
+ if (paramList->ParameterValues[i][shift + j] == v[j]) {
+ matched++;
+ swizzle[j] = shift + j;
+ }
+ }
+ if (matched == vSize) {
+ /* found! */
+ *posOut = i;
+ *swizzleOut = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+ swizzle[2], swizzle[3]);
+ return GL_TRUE;
+ }
+ }
+ }
+ }
+
+ return GL_FALSE;
+}
+
+
/**
* 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>
{
/* state[1] is either 0=front or 1=back side */
const GLuint face = (GLuint) state[1];
+ const struct gl_material *mat = &ctx->Light.Material;
+ ASSERT(face == 0 || face == 1);
+ /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */
+ ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT);
+ /* XXX we could get rid of this switch entirely with a little
+ * work in arbprogparse.c's parse_state_single_item().
+ */
/* 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]);
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]);
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]);
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]);
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]);
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]);
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]);
+ COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]);
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[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][0];
value[1] = 0.0F;
value[2] = 0.0F;
value[3] = 1.0F;
modifier == STATE_MATRIX_INVTRANS) {
/* Be sure inverse is up to date:
*/
+ _math_matrix_alloc_inv( (GLmatrix *) matrix );
_math_matrix_analyse( (GLmatrix*) matrix );
m = matrix->inv;
}
case STATE_NORMAL_SCALE:
ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
break;
+ case STATE_TEXRECT_SCALE: {
+ const int unit = (int) state[2];
+ const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
+ if (texObj) {
+ struct gl_texture_image *texImage = texObj->Image[0][0];
+ ASSIGN_4V(value, 1.0 / texImage->Width, 1.0 / texImage->Height, 0, 1);
+ }
+ break;
+ }
default:
- _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ /* unknown state indexes are silently ignored
+ * should be handled by the driver.
+ */
return;
}
}
}
+/**
+ * Return a bitmask of the Mesa state flags (_NEW_* values) which would
+ * indicate that the given context state may have changed.
+ * The bitmask is used during validation to determine if we need to update
+ * vertex/fragment program parameters (like "state.material.color") when
+ * some GL state has changed.
+ */
+static GLbitfield
+make_state_flags(const GLint state[])
+{
+ switch (state[0]) {
+ case STATE_MATERIAL:
+ case STATE_LIGHT:
+ case STATE_LIGHTMODEL_AMBIENT:
+ case STATE_LIGHTMODEL_SCENECOLOR:
+ case STATE_LIGHTPROD:
+ return _NEW_LIGHT;
+
+ case STATE_TEXGEN:
+ case STATE_TEXENV_COLOR:
+ return _NEW_TEXTURE;
+
+ case STATE_FOG_COLOR:
+ case STATE_FOG_PARAMS:
+ return _NEW_FOG;
+
+ case STATE_CLIPPLANE:
+ return _NEW_TRANSFORM;
+
+ case STATE_POINT_SIZE:
+ case STATE_POINT_ATTENUATION:
+ return _NEW_POINT;
+
+ case STATE_MATRIX:
+ switch (state[1]) {
+ case STATE_MODELVIEW:
+ return _NEW_MODELVIEW;
+ case STATE_PROJECTION:
+ return _NEW_PROJECTION;
+ case STATE_MVP:
+ return _NEW_MODELVIEW | _NEW_PROJECTION;
+ case STATE_TEXTURE:
+ return _NEW_TEXTURE_MATRIX;
+ case STATE_PROGRAM:
+ return _NEW_TRACK_MATRIX;
+ default:
+ _mesa_problem(NULL, "unexpected matrix in make_state_flags()");
+ return 0;
+ }
+
+ case STATE_DEPTH_RANGE:
+ return _NEW_VIEWPORT;
+
+ case STATE_FRAGMENT_PROGRAM:
+ case STATE_VERTEX_PROGRAM:
+ return _NEW_PROGRAM;
+
+ case STATE_INTERNAL:
+ switch (state[1]) {
+ case STATE_NORMAL_SCALE:
+ return _NEW_MODELVIEW;
+ case STATE_TEXRECT_SCALE:
+ return _NEW_TEXTURE;
+ default:
+ /* unknown state indexes are silently ignored and
+ * no flag set, since it is handled by the driver.
+ */
+ return 0;
+ }
+
+ default:
+ _mesa_problem(NULL, "unexpected state[0] in make_state_flags()");
+ return 0;
+ }
+}
+
+
static void
append(char *dst, const char *src)
{
*dst = 0;
}
+
static void
append_token(char *dst, enum state_index k)
{
/**
* Make a string from the given state vector.
* For example, return "state.matrix.texture[2].inverse".
+ * Use _mesa_free() to deallocate the string.
*/
static const char *
make_state_string(const GLint state[6])
char tmp[30];
append(str, "state.");
- append_token(str, state[0]);
+ append_token(str, (enum state_index) state[0]);
switch (state[0]) {
case STATE_MATERIAL:
append_face(str, state[1]);
- append_token(str, state[2]);
+ append_token(str, (enum state_index) state[2]);
break;
case STATE_LIGHT:
append(str, "light");
append_index(str, state[1]); /* light number [i]. */
- append_token(str, state[2]); /* coefficients */
+ append_token(str, (enum state_index) state[2]); /* coefficients */
break;
case STATE_LIGHTMODEL_AMBIENT:
append(str, "lightmodel.ambient");
case STATE_LIGHTPROD:
append_index(str, state[1]); /* light number [i]. */
append_face(str, state[2]);
- append_token(str, state[3]);
+ append_token(str, (enum state_index) state[3]);
break;
case STATE_TEXGEN:
append_index(str, state[1]); /* tex unit [i] */
- append_token(str, state[2]); /* plane coef */
+ append_token(str, (enum state_index) state[2]); /* plane coef */
break;
case STATE_TEXENV_COLOR:
append_index(str, state[1]); /* tex unit [i] */
/* state[3] = first column to fetch */
/* state[4] = last column to fetch */
/* state[5] = transpose, inverse or invtrans */
- const enum state_index mat = state[1];
+ const enum state_index mat = (enum state_index) 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 enum state_index modifier = (enum state_index) state[5];
append_token(str, mat);
if (index)
append_index(str, index);
case STATE_VERTEX_PROGRAM:
/* state[1] = {STATE_ENV, STATE_LOCAL} */
/* state[2] = parameter index */
- append_token(str, state[1]);
+ append_token(str, (enum state_index) state[1]);
append_index(str, state[2]);
break;
case STATE_INTERNAL:
break;
default:
- _mesa_problem(NULL, "Invalid state in maka_state_string");
+ _mesa_problem(NULL, "Invalid state in make_state_string");
break;
}
*/
void
_mesa_load_state_parameters(GLcontext *ctx,
- struct program_parameter_list *paramList)
+ struct gl_program_parameter_list *paramList)
{
GLuint i;
}
+/**
+ * Initialize program instruction fields to defaults.
+ * \param inst first instruction to initialize
+ * \param count number of instructions to initialize
+ */
+void
+_mesa_init_instructions(struct prog_instruction *inst, GLuint count)
+{
+ GLuint i;
+
+ _mesa_bzero(inst, count * sizeof(struct prog_instruction));
+
+ for (i = 0; i < count; i++) {
+ inst[i].SrcReg[0].File = PROGRAM_UNDEFINED;
+ inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
+ inst[i].SrcReg[1].File = PROGRAM_UNDEFINED;
+ inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+ inst[i].SrcReg[2].File = PROGRAM_UNDEFINED;
+ inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP;
+
+ inst[i].DstReg.File = PROGRAM_UNDEFINED;
+ inst[i].DstReg.WriteMask = WRITEMASK_XYZW;
+ inst[i].DstReg.CondMask = COND_TR;
+ inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP;
+
+ inst[i].SaturateMode = SATURATE_OFF;
+ inst[i].Precision = FLOAT32;
+ }
+}
+
+
+/**
+ * Allocate an array of program instructions.
+ * \param numInst number of instructions
+ * \return pointer to instruction memory
+ */
+struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst)
+{
+ return (struct prog_instruction *)
+ _mesa_calloc(numInst * sizeof(struct prog_instruction));
+}
+
+
+/**
+ * Reallocate memory storing an array of program instructions.
+ * This is used when we need to append additional instructions onto an
+ * program.
+ * \param oldInst pointer to first of old/src instructions
+ * \param numOldInst number of instructions at <oldInst>
+ * \param numNewInst desired size of new instruction array.
+ * \return pointer to start of new instruction array.
+ */
+struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+ GLuint numOldInst, GLuint numNewInst)
+{
+ struct prog_instruction *newInst;
+
+ newInst = (struct prog_instruction *)
+ _mesa_realloc(oldInst,
+ numOldInst * sizeof(struct prog_instruction),
+ numNewInst * sizeof(struct prog_instruction));
+
+ return newInst;
+}
+
+
/**
* Basic info about each instruction
*/
GLuint
_mesa_num_inst_src_regs(enum prog_opcode opcode)
{
- GLuint i;
-#ifdef DEBUG
- for (i = 0; i < MAX_OPCODE; i++) {
- ASSERT(i == InstInfo[i].Opcode);
- }
-#endif
- for (i = 0; i < MAX_OPCODE; i++) {
- if (InstInfo[i].Opcode == opcode) {
- return InstInfo[i].NumSrcRegs;
- }
- }
- _mesa_problem(NULL, "invalid opcode in _mesa_num_inst_src_regs");
- return 0;
+ ASSERT(opcode == InstInfo[opcode].Opcode);
+ return InstInfo[opcode].NumSrcRegs;
}
print_dst_reg(const struct prog_dst_register *dstReg)
{
_mesa_printf(" %s[%d]%s",
- program_file_string(dstReg->File),
+ program_file_string((enum register_file) dstReg->File),
dstReg->Index,
writemask_string(dstReg->WriteMask));
}
print_src_reg(const struct prog_src_register *srcReg)
{
_mesa_printf("%s[%d]%s",
- program_file_string(srcReg->File),
+ program_file_string((enum register_file) srcReg->File),
srcReg->Index,
swizzle_string(srcReg->Swizzle,
srcReg->NegateBase, GL_FALSE));
}
+void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+ const char *opcode_string,
+ GLuint numRegs)
+{
+ GLuint j;
+
+ _mesa_printf("%s", opcode_string);
+
+ /* frag prog only */
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
+ _mesa_printf("_SAT");
+
+ if (inst->DstReg.File != PROGRAM_UNDEFINED) {
+ _mesa_printf(" %s[%d]%s",
+ program_file_string((enum register_file) inst->DstReg.File),
+ inst->DstReg.Index,
+ writemask_string(inst->DstReg.WriteMask));
+ }
+
+ if (numRegs > 0)
+ _mesa_printf(", ");
+
+ for (j = 0; j < numRegs; j++) {
+ print_src_reg(inst->SrcReg + j);
+ if (j + 1 < numRegs)
+ _mesa_printf(", ");
+ }
+
+ _mesa_printf(";\n");
+}
+
/**
* Print a single vertex/fragment program instruction.
if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
_mesa_printf(", ");
_mesa_printf("%s[%d]%s",
- program_file_string(inst->SrcReg[0].File),
+ program_file_string((enum register_file) inst->SrcReg[0].File),
inst->SrcReg[0].Index,
swizzle_string(inst->SrcReg[0].Swizzle,
inst->SrcReg[0].NegateBase, GL_FALSE));
break;
case OPCODE_SWZ:
_mesa_printf("SWZ");
- if (inst->Saturate)
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
_mesa_printf("_SAT");
print_dst_reg(&inst->DstReg);
_mesa_printf("%s[%d], %s;\n",
- program_file_string(inst->SrcReg[0].File),
+ program_file_string((enum register_file) inst->SrcReg[0].File),
inst->SrcReg[0].Index,
swizzle_string(inst->SrcReg[0].Swizzle,
inst->SrcReg[0].NegateBase, GL_TRUE));
case OPCODE_TXP:
case OPCODE_TXB:
_mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
- if (inst->Saturate)
+ if (inst->SaturateMode == SATURATE_ZERO_ONE)
_mesa_printf("_SAT");
_mesa_printf(" ");
print_dst_reg(&inst->DstReg);
print_src_reg(&inst->SrcReg[0]);
_mesa_printf(";\n");
break;
+ case OPCODE_END:
+ _mesa_printf("END;\n");
+ break;
/* XXX may need for other special-case instructions */
default:
/* typical alu instruction */
- {
- const GLuint numRegs = _mesa_num_inst_src_regs(inst->Opcode);
- GLuint j;
-
- _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
-
- /* frag prog only */
- if (inst->Saturate)
- _mesa_printf("_SAT");
-
- if (inst->DstReg.File != PROGRAM_UNDEFINED) {
- _mesa_printf(" %s[%d]%s",
- program_file_string(inst->DstReg.File),
- inst->DstReg.Index,
- writemask_string(inst->DstReg.WriteMask));
- }
-
- if (numRegs > 0)
- _mesa_printf(", ");
-
- for (j = 0; j < numRegs; j++) {
- print_src_reg(inst->SrcReg + j);
- if (j + 1 < numRegs)
- _mesa_printf(", ");
- }
-
- _mesa_printf(";\n");
- }
+ _mesa_print_alu_instruction(inst,
+ _mesa_opcode_string(inst->Opcode),
+ _mesa_num_inst_src_regs(inst->Opcode));
+ break;
}
}
* XXX this function could be greatly improved.
*/
void
-_mesa_print_program(const struct program *prog)
+_mesa_print_program(const struct gl_program *prog)
{
GLuint i;
for (i = 0; i < prog->NumInstructions; i++) {
* Print all of a program's parameters.
*/
void
-_mesa_print_program_parameters(GLcontext *ctx, const struct program *prog)
+_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
{
GLint i;
#endif
for (i = 0; i < prog->Parameters->NumParameters; i++){
- struct program_parameter *param = prog->Parameters->Parameters + i;
+ struct gl_program_parameter *param = prog->Parameters->Parameters + i;
const GLfloat *v = prog->Parameters->ParameterValues[i];
_mesa_printf("param[%d] %s = {%.3f, %.3f, %.3f, %.3f};\n",
i, param->Name, v[0], v[1], v[2], v[3]);
}
+/**
+ * Mixing ARB and NV vertex/fragment programs can be tricky.
+ * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
+ * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
+ * The two different fragment program targets are supposed to be compatible
+ * to some extent (see GL_ARB_fragment_program spec).
+ * This function does the compatibility check.
+ */
+static GLboolean
+compatible_program_targets(GLenum t1, GLenum t2)
+{
+ if (t1 == t2)
+ return GL_TRUE;
+ if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
+ return GL_TRUE;
+ if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
+ return GL_TRUE;
+ return GL_FALSE;
+}
+
+
/**********************************************************************/
/* API functions */
void GLAPIENTRY
_mesa_BindProgram(GLenum target, GLuint id)
{
- struct program *prog;
+ struct gl_program *curProg, *newProg;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- if ((target == GL_VERTEX_PROGRAM_NV
- && ctx->Extensions.NV_vertex_program) ||
- (target == GL_VERTEX_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program)) {
- /*** Vertex program binding ***/
- struct vertex_program *curProg = ctx->VertexProgram.Current;
- if (curProg->Base.Id == id) {
- /* binding same program - no change */
- return;
- }
- if (curProg->Base.Id != 0) {
- /* decrement refcount on previously bound vertex program */
- curProg->Base.RefCount--;
- /* and delete if refcount goes below one */
- if (curProg->Base.RefCount <= 0) {
- /* the program ID was already removed from the hash table */
- ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
- }
- }
+ /* Error-check target and get curProg */
+ if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
+ (ctx->Extensions.NV_vertex_program ||
+ ctx->Extensions.ARB_vertex_program)) {
+ curProg = &ctx->VertexProgram.Current->Base;
}
else if ((target == GL_FRAGMENT_PROGRAM_NV
&& ctx->Extensions.NV_fragment_program) ||
(target == GL_FRAGMENT_PROGRAM_ARB
&& ctx->Extensions.ARB_fragment_program)) {
- /*** Fragment program binding ***/
- struct fragment_program *curProg = ctx->FragmentProgram.Current;
- if (curProg->Base.Id == id) {
- /* binding same program - no change */
- return;
- }
- if (curProg->Base.Id != 0) {
- /* decrement refcount on previously bound fragment program */
- curProg->Base.RefCount--;
- /* and delete if refcount goes below one */
- if (curProg->Base.RefCount <= 0) {
- /* the program ID was already removed from the hash table */
- ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
- }
- }
+ curProg = &ctx->FragmentProgram.Current->Base;
}
else {
_mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
return;
}
- /* NOTE: binding to a non-existant program is not an error.
+ /*
+ * Get pointer to new program to bind.
+ * NOTE: binding to a non-existant program is not an error.
* That's supposed to be caught in glBegin.
*/
if (id == 0) {
- /* Bind default program */
- prog = NULL;
- if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
- prog = ctx->Shared->DefaultVertexProgram;
+ /* Bind a default program */
+ newProg = NULL;
+ if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
+ newProg = ctx->Shared->DefaultVertexProgram;
else
- prog = ctx->Shared->DefaultFragmentProgram;
+ newProg = ctx->Shared->DefaultFragmentProgram;
}
else {
- /* Bind user program */
- prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
- if (!prog || prog == &_mesa_DummyProgram) {
+ /* Bind a user program */
+ newProg = _mesa_lookup_program(ctx, id);
+ if (!newProg || newProg == &_mesa_DummyProgram) {
/* allocate a new program now */
- prog = ctx->Driver.NewProgram(ctx, target, id);
- if (!prog) {
+ newProg = ctx->Driver.NewProgram(ctx, target, id);
+ if (!newProg) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
return;
}
- _mesa_HashInsert(ctx->Shared->Programs, id, prog);
+ _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
}
- else if (prog->Target != target) {
+ else if (!compatible_program_targets(newProg->Target, target)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBindProgramNV/ARB(target mismatch)");
return;
}
}
- /* bind now */
- if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
- ctx->VertexProgram.Current = (struct vertex_program *) prog;
+ /** All error checking is complete now **/
+
+ if (curProg->Id == id) {
+ /* binding same program - no change */
+ return;
+ }
+
+ /* unbind/delete oldProg */
+ if (curProg->Id != 0) {
+ /* decrement refcount on previously bound fragment program */
+ curProg->RefCount--;
+ /* and delete if refcount goes below one */
+ if (curProg->RefCount <= 0) {
+ /* the program ID was already removed from the hash table */
+ ctx->Driver.DeleteProgram(ctx, curProg);
+ }
+ }
+
+ /* bind newProg */
+ if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
+ if (ctx->VertexProgram._Current == ctx->VertexProgram.Current)
+ ctx->VertexProgram._Current = (struct gl_vertex_program *) newProg;
+ ctx->VertexProgram.Current = (struct gl_vertex_program *) newProg;
}
- else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
- ctx->FragmentProgram.Current = (struct fragment_program *) prog;
+ else if (target == GL_FRAGMENT_PROGRAM_NV ||
+ target == GL_FRAGMENT_PROGRAM_ARB) {
+ ctx->FragmentProgram.Current = (struct gl_fragment_program *) newProg;
}
+ newProg->RefCount++;
/* Never null pointers */
ASSERT(ctx->VertexProgram.Current);
ASSERT(ctx->FragmentProgram.Current);
- if (prog)
- prog->RefCount++;
-
if (ctx->Driver.BindProgram)
- ctx->Driver.BindProgram(ctx, target, prog);
+ ctx->Driver.BindProgram(ctx, target, newProg);
}
* \note Not compiled into display lists.
* \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
*/
-void GLAPIENTRY
+void GLAPIENTRY
_mesa_DeletePrograms(GLsizei n, const GLuint *ids)
{
GLint i;
for (i = 0; i < n; i++) {
if (ids[i] != 0) {
- struct program *prog = (struct program *)
- _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
+ struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
if (prog == &_mesa_DummyProgram) {
_mesa_HashRemove(ctx->Shared->Programs, ids[i]);
}
else if (prog) {
/* Unbind program if necessary */
- if (prog->Target == GL_VERTEX_PROGRAM_NV ||
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */
prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
if (ctx->VertexProgram.Current &&
ctx->VertexProgram.Current->Base.Id == ids[i]) {
}
-/**
- * Determine if id names a vertex or fragment program.
- * \note Not compiled into display lists.
- * \note Called from both glIsProgramNV and glIsProgramARB.
- * \param id is the program identifier
- * \return GL_TRUE if id is a program, else GL_FALSE.
- */
-GLboolean GLAPIENTRY
-_mesa_IsProgram(GLuint id)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-
- if (id == 0)
- return GL_FALSE;
-
- if (_mesa_HashLookup(ctx->Shared->Programs, id))
- return GL_TRUE;
- else
- return GL_FALSE;
-}
-
-
-
/**********************************************************************/
/* GL_MESA_program_debug extension */
/**********************************************************************/
reg[len] = 0;
switch (target) {
- case GL_VERTEX_PROGRAM_NV:
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
if (!ctx->Extensions.ARB_vertex_program &&
!ctx->Extensions.NV_vertex_program) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glGetProgramRegisterfvMESA(registerName)");
return;
}
- COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
+#if 0 /* FIX ME */
+ ctx->Driver.GetVertexProgramRegister(ctx, PROGRAM_TEMPORARY, i, v);
+#endif
}
else if (reg[0] == 'v' && reg[1] == '[') {
/* Vertex Input attribute */
_mesa_sprintf(number, "%d", i);
if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
_mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
- COPY_4V(v, ctx->VertexProgram.Inputs[i]);
+#if 0 /* FIX ME */
+ ctx->Driver.GetVertexProgramRegister(ctx, PROGRAM_INPUT,
+ i, v);
+#endif
return;
}
}
"glGetProgramRegisterfvMESA(registerName)");
return;
}
- COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
+ ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_TEMPORARY,
+ i, v);
}
else if (reg[0] == 'f' && reg[1] == '[') {
/* Fragment input attribute */
for (i = 0; i < ctx->Const.FragmentProgram.MaxAttribs; i++) {
const char *name = _mesa_nv_fragment_input_register_name(i);
if (_mesa_strncmp(reg + 2, name, 4) == 0) {
- COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
+ ctx->Driver.GetFragmentProgramRegister(ctx,
+ PROGRAM_INPUT, i, v);
return;
}
}
}
else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
/* Fragment output color */
- COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLR]);
+ ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+ FRAG_RESULT_COLR, v);
}
else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
/* Fragment output color */
- COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLH]);
+ ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+ FRAG_RESULT_COLH, v);
}
else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
/* Fragment output depth */
- COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_DEPR]);
+ ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+ FRAG_RESULT_DEPR, v);
}
else {
/* try user-defined identifiers */
"glGetProgramRegisterfvMESA(target)");
return;
}
-
}