/*
* Mesa 3-D graphics library
- * Version: 6.1
+ * Version: 6.2
*
* Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
*
#include "nvfragparse.h"
#include "nvfragprog.h"
#include "nvvertparse.h"
+#include "nvvertprog.h"
/**********************************************************************/
/**********************************************************************/
+/* A pointer to this dummy program is put into the hash table when
+ * glGenPrograms is called.
+ */
+struct program _mesa_DummyProgram;
+
+
/**
- * Init context's program state
+ * Init context's vertex/fragment program state
*/
void
_mesa_init_program(GLcontext *ctx)
assert(ctx->FragmentProgram.Current);
ctx->FragmentProgram.Current->Base.RefCount++;
#endif
+
+#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++;
+#endif
+}
+
+
+/**
+ * Free a context's vertex/fragment program state
+ */
+void
+_mesa_free_program_data(GLcontext *ctx)
+{
+#if FEATURE_NV_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 (ctx->FragmentProgram.Current) {
+ ctx->FragmentProgram.Current->Base.RefCount--;
+ if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
+ ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
+ }
+#endif
+#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));
+ }
+#endif
+ _mesa_free((void *) ctx->Program.ErrorString);
}
+
+
/**
* Set the vertex/fragment program error state (position and error string).
* This is generally called from within the parsers.
}
-static struct program * _mesa_init_program_struct( GLcontext *ctx,
- struct program *prog,
- GLenum target, GLuint id)
+/**
+ * Initialize a new vertex/fragment program object.
+ */
+static struct program *
+_mesa_init_program_struct( GLcontext *ctx, struct program *prog,
+ GLenum target, GLuint id)
{
+ (void) ctx;
if (prog) {
prog->Id = id;
prog->Target = target;
return prog;
}
-struct program * _mesa_init_fragment_program( GLcontext *ctx,
- struct fragment_program *prog,
- GLenum target, GLuint id)
+
+/**
+ * Initialize a new fragment program object.
+ */
+struct program *
+_mesa_init_fragment_program( GLcontext *ctx, struct fragment_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Initialize a new vertex program object.
+ */
+struct program *
+_mesa_init_vertex_program( GLcontext *ctx, struct vertex_program *prog,
+ GLenum target, GLuint id)
{
if (prog)
return _mesa_init_program_struct( ctx, &prog->Base, target, id );
return NULL;
}
-struct program * _mesa_init_vertex_program( GLcontext *ctx,
- struct vertex_program *prog,
- GLenum target, GLuint id)
+/**
+ * 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 );
}
+
/**
* Allocate and initialize a new fragment/vertex program object but
* don't put it into the program hash table. Called via
case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(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 );
default:
_mesa_problem(ctx, "bad target in _mesa_new_program");
void
_mesa_delete_program(GLcontext *ctx, struct program *prog)
{
+ (void) ctx;
ASSERT(prog);
if (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)
+ if (vprog->Instructions) {
+ GLuint i;
+ for (i = 0; i < vprog->Base.NumInstructions; i++) {
+ if (vprog->Instructions[i].Data)
+ _mesa_free(vprog->Instructions[i].Data);
+ }
_mesa_free(vprog->Instructions);
+ }
+ if (vprog->Parameters)
+ _mesa_free_parameter_list(vprog->Parameters);
}
else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
struct fragment_program *fprog = (struct fragment_program *) prog;
- if (fprog->Instructions)
+ if (fprog->Instructions) {
+ GLuint i;
+ for (i = 0; i < fprog->Base.NumInstructions; i++) {
+ if (fprog->Instructions[i].Data)
+ _mesa_free(fprog->Instructions[i].Data);
+ }
_mesa_free(fprog->Instructions);
- if (fprog->Parameters) {
- _mesa_free_parameter_list(fprog->Parameters);
}
+ if (fprog->Parameters)
+ _mesa_free_parameter_list(fprog->Parameters);
}
+ else if (prog->Target == GL_FRAGMENT_SHADER_ATI) {
+ struct ati_fragment_shader *atifs = (struct ati_fragment_shader *)prog;
+ if (atifs->Instructions)
+ _mesa_free(atifs->Instructions);
+ }
+
_mesa_free(prog);
}
_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);
}
{
GLuint i;
for (i = 0; i < paramList->NumParameters; i++) {
- _mesa_free((void *) paramList->Parameters[i].Name);
+ if (paramList->Parameters[i].Name)
+ _mesa_free((void *) paramList->Parameters[i].Name);
}
- _mesa_free(paramList->Parameters);
paramList->NumParameters = 0;
- paramList->Parameters = NULL;
}
{
const GLuint n = paramList->NumParameters;
- paramList->Parameters = (struct program_parameter *)
- _mesa_realloc(paramList->Parameters,
- n * sizeof(struct program_parameter),
- (n + 1) * sizeof(struct program_parameter));
- if (!paramList->Parameters) {
+ if (n == paramList->Size) {
+ GLfloat (*tmp)[4];
+
+ paramList->Size *= 2;
+ if (!paramList->Size)
+ paramList->Size = 8;
+
+ paramList->Parameters = (struct 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);
+ }
+ }
+
+ if (!paramList->Parameters ||
+ !paramList->ParameterValues) {
/* out of memory */
paramList->NumParameters = 0;
+ paramList->Size = 0;
return -1;
}
else {
paramList->NumParameters = n + 1;
- paramList->Parameters[n].Name = _mesa_strdup(name);
+
+ _mesa_memset(¶mList->Parameters[n], 0,
+ sizeof(struct program_parameter));
+
+ paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
paramList->Parameters[n].Type = type;
if (values)
- COPY_4V(paramList->Parameters[n].Values, values);
+ COPY_4V(paramList->ParameterValues[n], values);
return (GLint) n;
}
}
_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);
+ return add_parameter(paramList, NULL, values, CONSTANT);
}
*/
GLint a, idx;
- idx = add_parameter(paramList, "Some State", NULL, STATE);
+ idx = add_parameter(paramList, NULL, NULL, STATE);
for (a=0; a<6; a++)
paramList->Parameters[idx].StateIndexes[a] = (enum state_index) stateTokens[a];
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;
+ if (paramList->Parameters[i].Name &&
+ _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
+ return paramList->ParameterValues[i];
}
}
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
+ if (paramList->Parameters[i].Name &&
+ _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
&& _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
- return paramList->Parameters[i].Values;
+ return paramList->ParameterValues[i];
}
}
return NULL;
if (nameLen == -1) {
/* name is null-terminated */
for (i = 0; i < (GLint) paramList->NumParameters; i++) {
- if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
+ if (paramList->Parameters[i].Name &&
+ _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
+ if (paramList->Parameters[i].Name &&
+ _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
&& _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
return i;
}
_mesa_problem(ctx, "Invalid material state in fetch_state");
return;
}
- };
- return;
+ }
case STATE_LIGHT:
{
/* state[1] is the light number */
value[3] = ctx->Light.Light[ln].SpotExponent;
return;
case STATE_SPOT_DIRECTION:
- COPY_4V(value, ctx->Light.Light[ln].EyeDirection);
+ COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
+ value[3] = ctx->Light.Light[ln]._CosCutoff;
return;
case STATE_HALF:
{
/* Compute infinite half angle vector:
* half-vector = light_position + (0, 0, 1)
* and then normalize. w = 0
- *
- * light.EyePosition.w should be 0 for infinite lights.
+ *
+ * light.EyePosition.w should be 0 for infinite lights.
*/
- ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
- NORMALIZE_3FV(value);
- value[3] = 0;
+ ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
+ NORMALIZE_3FV(value);
+ value[3] = 0;
}
return;
+ case STATE_POSITION_NORMALIZED:
+ COPY_4V(value, ctx->Light.Light[ln].EyePosition);
+ NORMALIZE_3FV( value );
+ 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;
if (state[1] == 0) {
/* front */
GLint i;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 3; 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];
}
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
}
else {
/* back */
GLint i;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 3; 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];
}
+ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
}
return;
case STATE_LIGHTPROD:
return;
}
}
- return;
case STATE_TEXGEN:
{
/* state[1] is the texture unit */
return;
}
}
- return;
case STATE_TEXENV_COLOR:
{
/* state[1] is the texture unit */
}
if (modifier == STATE_MATRIX_INVERSE ||
modifier == STATE_MATRIX_INVTRANS) {
- /* XXX be sure inverse is up to date */
+ /* Be sure inverse is up to date:
+ */
+ _math_matrix_analyse( (GLmatrix*) matrix );
m = matrix->inv;
}
else {
}
return;
case STATE_DEPTH_RANGE:
- value[0] = ctx->Viewport.Near; /* near */
- value[1] = ctx->Viewport.Far; /* far */
- value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
- value[3] = 0;
+ value[0] = ctx->Viewport.Near; /* near */
+ value[1] = ctx->Viewport.Far; /* far */
+ value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
+ value[3] = 0;
return;
case STATE_FRAGMENT_PROGRAM:
{
/* state[1] = {STATE_ENV, STATE_LOCAL} */
/* state[2] = parameter index */
- int idx = state[2];
-
+ const int idx = (int) state[2];
switch (state[1]) {
case STATE_ENV:
- COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
+ COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
break;
-
case STATE_LOCAL:
COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
- break;
+ break;
default:
_mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
return;
- }
- }
+ }
+ }
return;
case STATE_VERTEX_PROGRAM:
- {
+ {
/* state[1] = {STATE_ENV, STATE_LOCAL} */
/* state[2] = parameter index */
- int idx = state[2];
-
+ const int idx = (int) state[2];
switch (state[1]) {
case STATE_ENV:
- COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
+ COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
break;
-
case STATE_LOCAL:
COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
- break;
+ break;
default:
_mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
return;
- }
- }
+ }
+ }
return;
+
+ case STATE_INTERNAL:
+ {
+ switch (state[1]) {
+ case STATE_NORMAL_SCALE:
+ ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+ return;
+ }
+ }
+ return;
+
default:
- _mesa_problem(ctx, "Invalid state in fetch_state");
+ _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
return;
}
}
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);
+ _mesa_fetch_state(ctx,
+ paramList->Parameters[i].StateIndexes,
+ paramList->ParameterValues[i]);
}
}
}
&& 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)
+ /*** Vertex program binding ***/
+ struct vertex_program *curProg = ctx->VertexProgram.Current;
+ if (curProg->Base.Id == id) {
+ /* binding same program - no change */
return;
- /* decrement refcount on previously bound vertex program */
- if (ctx->VertexProgram.Current) {
- ctx->VertexProgram.Current->Base.RefCount--;
+ }
+ if (curProg->Base.Id != 0) {
+ /* decrement refcount on previously bound vertex program */
+ curProg->Base.RefCount--;
/* and delete if refcount goes below one */
- if (ctx->VertexProgram.Current->Base.RefCount <= 0) {
- ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
- _mesa_HashRemove(ctx->Shared->Programs, id);
+ if (curProg->Base.RefCount <= 0) {
+ /* the program ID was already removed from the hash table */
+ ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
}
}
}
&& 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)
+ /*** Fragment program binding ***/
+ struct fragment_program *curProg = ctx->FragmentProgram.Current;
+ if (curProg->Base.Id == id) {
+ /* binding same program - no change */
return;
- /* decrement refcount on previously bound fragment program */
- if (ctx->FragmentProgram.Current) {
- ctx->FragmentProgram.Current->Base.RefCount--;
+ }
+ if (curProg->Base.Id != 0) {
+ /* decrement refcount on previously bound fragment program */
+ curProg->Base.RefCount--;
/* and delete if refcount goes below one */
- if (ctx->FragmentProgram.Current->Base.RefCount <= 0) {
- ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
- _mesa_HashRemove(ctx->Shared->Programs, id);
+ if (curProg->Base.RefCount <= 0) {
+ /* the program ID was already removed from the hash table */
+ ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
}
}
}
* That's supposed to be caught in glBegin.
*/
if (id == 0) {
- /* default program */
+ /* Bind default program */
prog = NULL;
if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
prog = ctx->Shared->DefaultVertexProgram;
prog = ctx->Shared->DefaultFragmentProgram;
}
else {
+ /* Bind user program */
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 {
+ if (!prog || prog == &_mesa_DummyProgram) {
/* allocate a new program now */
prog = ctx->Driver.NewProgram(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);
}
+ else if (prog->Target != target) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindProgramNV/ARB(target mismatch)");
+ return;
+ }
}
/* bind now */
ctx->FragmentProgram.Current = (struct fragment_program *) prog;
}
+ /* Never null pointers */
+ ASSERT(ctx->VertexProgram.Current);
+ ASSERT(ctx->FragmentProgram.Current);
+
if (prog)
prog->RefCount++;
if (ids[i] != 0) {
struct program *prog = (struct program *)
_mesa_HashLookup(ctx->Shared->Programs, ids[i]);
- if (prog) {
+ 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 ||
prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
if (ctx->VertexProgram.Current &&
_mesa_problem(ctx, "bad target in glDeleteProgramsNV");
return;
}
+ /* The ID is immediately available for re-use now */
+ _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
prog->RefCount--;
if (prog->RefCount <= 0) {
ctx->Driver.DeleteProgram(ctx, prog);
}
}
- else {
- /* This is necessary as we can't tell from HashLookup
- * whether the entry exists with data == 0, or if it
- * doesn't exist at all. As GenPrograms creates the first
- * case below, need to call Remove() to avoid memory leak:
- */
- _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
- }
}
}
}
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
+ /* Insert pointer to dummy program as placeholder */
for (i = 0; i < (GLuint) n; i++) {
- _mesa_HashInsert(ctx->Shared->Programs, first + i, 0);
+ _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
}
/* Return the program names */
/**
- * Determine if id names a program.
+ * 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
/* XXX temporary */
-void
+GLAPI void GLAPIENTRY
glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
GLvoid *data)
{
/* XXX temporary */
-void
+GLAPI void GLAPIENTRY
glGetProgramRegisterfvMESA(GLenum target,
GLsizei len, const GLubyte *registerName,
GLfloat *v)