X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fshader%2Fprogram.c;h=723c46ee8cf7f83f47229d7380a91124ab00f9c6;hb=2a6c12cf532b5206cebf6d643ab6e970a949b874;hp=826fb739c0bf7e4b46bd1cfa4494786216bd8e4b;hpb=a360bc31dad079d4d1100aa84857758e3d9d6308;p=mesa.git diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 826fb739c0b..723c46ee8cf 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 6.5.1 + * Version: 6.5.3 * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -29,32 +29,17 @@ */ -#include "glheader.h" -#include "context.h" -#include "hash.h" -#include "imports.h" -#include "macros.h" -#include "mtypes.h" +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" #include "program.h" -#include "nvfragparse.h" -#include "program_instruction.h" -#include "nvvertparse.h" -#include "atifragshader.h" +#include "prog_cache.h" +#include "prog_parameter.h" +#include "prog_instruction.h" -static const char * -make_state_string(const GLint stateTokens[6]); - -static GLuint -make_state_flags(const GLint state[]); - - -/**********************************************************************/ -/* Utility functions */ -/**********************************************************************/ - - -/* A pointer to this dummy program is put into the hash table when +/** + * A pointer to this dummy program is put into the hash table when * glGenPrograms is called. */ struct gl_program _mesa_DummyProgram; @@ -73,28 +58,35 @@ _mesa_init_program(GLcontext *ctx) #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program ctx->VertexProgram.Enabled = GL_FALSE; +#if FEATURE_es2_glsl + ctx->VertexProgram.PointSizeEnabled = GL_TRUE; +#else ctx->VertexProgram.PointSizeEnabled = GL_FALSE; +#endif ctx->VertexProgram.TwoSideEnabled = GL_FALSE; - ctx->VertexProgram.Current = (struct gl_vertex_program *) ctx->Shared->DefaultVertexProgram; + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + 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; } + ctx->VertexProgram.Cache = _mesa_new_program_cache(); #endif #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program ctx->FragmentProgram.Enabled = GL_FALSE; - ctx->FragmentProgram.Current = (struct gl_fragment_program *) ctx->Shared->DefaultFragmentProgram; + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + ctx->Shared->DefaultFragmentProgram); assert(ctx->FragmentProgram.Current); - ctx->FragmentProgram.Current->Base.RefCount++; + ctx->FragmentProgram.Cache = _mesa_new_program_cache(); #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; + ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; assert(ctx->ATIFragmentShader.Current); ctx->ATIFragmentShader.Current->RefCount++; #endif @@ -108,18 +100,12 @@ void _mesa_free_program_data(GLcontext *ctx) { #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)); - } + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); + _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); #endif #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)); - } + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); + _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache); #endif /* XXX probably move this stuff */ #if FEATURE_ATI_fragment_shader @@ -134,8 +120,6 @@ _mesa_free_program_data(GLcontext *ctx) } - - /** * Set the vertex/fragment program error state (position and error string). * This is generally called from within the parsers. @@ -203,10 +187,17 @@ _mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog, { (void) ctx; if (prog) { + GLuint i; + _mesa_bzero(prog, sizeof(*prog)); prog->Id = id; prog->Target = target; prog->Resident = GL_TRUE; prog->RefCount = 1; + prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; + + /* default mapping from samplers to texture units */ + for (i = 0; i < MAX_SAMPLERS; i++) + prog->SamplerUnits[i] = i; } return prog; @@ -283,22 +274,32 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog) { (void) ctx; ASSERT(prog); + ASSERT(prog->RefCount==0); + if (prog == &_mesa_DummyProgram) + return; + if (prog->String) _mesa_free(prog->String); - if (prog->Instructions) { - GLuint i; - for (i = 0; i < prog->NumInstructions; i++) { - if (prog->Instructions[i].Data) - _mesa_free(prog->Instructions[i].Data); - } - _mesa_free(prog->Instructions); - } + _mesa_free_instructions(prog->Instructions, prog->NumInstructions); if (prog->Parameters) { _mesa_free_parameter_list(prog->Parameters); } + if (prog->Varying) { + _mesa_free_parameter_list(prog->Varying); + } + if (prog->Attributes) { + _mesa_free_parameter_list(prog->Attributes); + } + + /* 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); } @@ -319,1881 +320,397 @@ _mesa_lookup_program(GLcontext *ctx, GLuint id) } -/**********************************************************************/ -/* Program parameter functions */ -/**********************************************************************/ - -struct gl_program_parameter_list * -_mesa_new_parameter_list(void) -{ - return (struct gl_program_parameter_list *) - _mesa_calloc(sizeof(struct gl_program_parameter_list)); -} - - /** - * Free a parameter list and all its parameters + * Reference counting for vertex/fragment programs */ void -_mesa_free_parameter_list(struct gl_program_parameter_list *paramList) +_mesa_reference_program(GLcontext *ctx, + struct gl_program **ptr, + struct gl_program *prog) { - GLuint i; - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Name) - _mesa_free((void *) paramList->Parameters[i].Name); + assert(ptr); + if (*ptr && prog) { + /* sanity check */ + ASSERT((*ptr)->Target == prog->Target); } - _mesa_free(paramList->Parameters); - if (paramList->ParameterValues) - _mesa_align_free(paramList->ParameterValues); - _mesa_free(paramList); -} - - -/** - * 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 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) { - /* Need to grow the parameter list array */ - if (paramList->Size == 0) - paramList->Size = 8; - else - paramList->Size *= 2; - - /* realloc arrays */ - paramList->Parameters = (struct gl_program_parameter *) - _mesa_realloc(paramList->Parameters, - 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 (*ptr == prog) { + return; /* no change */ } + if (*ptr) { + GLboolean deleteFlag; - if (!paramList->Parameters || - !paramList->ParameterValues) { - /* out of memory */ - paramList->NumParameters = 0; - paramList->Size = 0; - return -1; - } - else { - paramList->NumParameters = n + 1; + /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ +#if 0 + printf("Program %p %u 0x%x Refcount-- to %d\n", + *ptr, (*ptr)->Id, (*ptr)->Target, (*ptr)->RefCount - 1); +#endif + ASSERT((*ptr)->RefCount > 0); + (*ptr)->RefCount--; - _mesa_memset(¶mList->Parameters[n], 0, - sizeof(struct gl_program_parameter)); + deleteFlag = ((*ptr)->RefCount == 0); + /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/ + + if (deleteFlag) { + ASSERT(ctx); + ctx->Driver.DeleteProgram(ctx, *ptr); + } - paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL; - paramList->Parameters[n].Type = type; - if (values) - COPY_4V(paramList->ParameterValues[n], values); - return (GLint) n; + *ptr = NULL; } -} - - -/** - * 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 gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4]) -{ - return add_parameter(paramList, name, values, PROGRAM_NAMED_PARAM); -} - -/** - * 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 values - four float values - * \return index of the new parameter. - */ -GLint -_mesa_add_named_constant(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4]) -{ - return add_parameter(paramList, name, values, PROGRAM_CONSTANT); -} - - -/** - * Add a new unnamed constant to the parameter list. - * 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 of the new parameter. - */ -GLint -_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, - const GLfloat values[4]) -{ - return add_parameter(paramList, NULL, values, PROGRAM_CONSTANT); -} - - -/** - * Add a new state reference to the parameter list. - * 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 gl_program_parameter_list *paramList, - const GLint *stateTokens) -{ - /* XXX we should probably search the current parameter list to see if - * the new state reference is already present. - */ - GLint index; - const char *name = make_state_string(stateTokens); - - index = add_parameter(paramList, name, NULL, PROGRAM_STATE_VAR); - if (index >= 0) { - GLuint i; - for (i = 0; i < 6; i++) { - paramList->Parameters[index].StateIndexes[i] - = (enum state_index) stateTokens[i]; - } - paramList->StateFlags |= - make_state_flags(stateTokens); + assert(!*ptr); + if (prog) { + /*_glthread_LOCK_MUTEX(prog->Mutex);*/ + prog->RefCount++; +#if 0 + printf("Program %p %u 0x%x Refcount++ to %d\n", + prog, prog->Id, prog->Target, prog->RefCount); +#endif + /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/ } - /* free name string here since we duplicated it in add_parameter() */ - _mesa_free((void *) name); - - return index; + *ptr = prog; } /** - * Lookup a parameter value by name in the given parameter list. - * \return pointer to the float[4] values. + * Return a copy of a program. + * XXX Problem here if the program object is actually OO-derivation + * made by a device driver. */ -GLfloat * -_mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name) +struct gl_program * +_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) { - GLuint i; + struct gl_program *clone; - if (!paramList) + clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); + if (!clone) return NULL; - if (nameLen == -1) { - /* name is null-terminated */ - for (i = 0; i < paramList->NumParameters; i++) { - 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 (paramList->Parameters[i].Name && - _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 - && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen) - return paramList->ParameterValues[i]; - } - } - return NULL; -} - + assert(clone->Target == prog->Target); + assert(clone->RefCount == 1); -/** - * Lookup a parameter index by name in the given parameter list. - * \return index of parameter in the list. - */ -GLint -_mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList, - GLsizei nameLen, const char *name) -{ - GLint i; - - if (!paramList) - return -1; - - if (nameLen == -1) { - /* name is null-terminated */ - for (i = 0; i < (GLint) paramList->NumParameters; i++) { - 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 (paramList->Parameters[i].Name && - _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 - && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen) - return i; - } + clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); + clone->Format = prog->Format; + clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); + if (!clone->Instructions) { + _mesa_reference_program(ctx, &clone, NULL); + return NULL; } - return -1; -} - - -/** - * Use the list of tokens in the state[] array to find global GL state - * and return it in . Usually, four values are returned in - * but matrix queries may return as many as 16 values. - * This function is used for ARB vertex/fragment programs. - * The program parser will produce the state[] values. - */ -static void -_mesa_fetch_state(GLcontext *ctx, const enum state_index state[], - GLfloat *value) -{ - switch (state[0]) { - case STATE_MATERIAL: - { - /* state[1] is either 0=front or 1=back side */ - const GLuint face = (GLuint) state[1]; - /* state[2] is the material attribute */ - switch (state[2]) { - case STATE_AMBIENT: - if (face == 0) - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]); - else - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]); - return; - case STATE_DIFFUSE: - if (face == 0) - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]); - else - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]); - return; - case STATE_SPECULAR: - if (face == 0) - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]); - else - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]); - return; - case STATE_EMISSION: - if (face == 0) - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]); - else - COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]); - return; - case STATE_SHININESS: - if (face == 0) - value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0]; - else - value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0]; - value[1] = 0.0F; - value[2] = 0.0F; - value[3] = 1.0F; - return; - default: - _mesa_problem(ctx, "Invalid material state in fetch_state"); - return; - } - } - case STATE_LIGHT: + _mesa_copy_instructions(clone->Instructions, prog->Instructions, + prog->NumInstructions); + clone->InputsRead = prog->InputsRead; + clone->OutputsWritten = prog->OutputsWritten; + clone->SamplersUsed = prog->SamplersUsed; + memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); + + if (prog->Parameters) + clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); + memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); + if (prog->Varying) + clone->Varying = _mesa_clone_parameter_list(prog->Varying); + if (prog->Attributes) + clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); + memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); + clone->NumInstructions = prog->NumInstructions; + clone->NumTemporaries = prog->NumTemporaries; + clone->NumParameters = prog->NumParameters; + clone->NumAttributes = prog->NumAttributes; + clone->NumAddressRegs = prog->NumAddressRegs; + clone->NumNativeInstructions = prog->NumNativeInstructions; + clone->NumNativeTemporaries = prog->NumNativeTemporaries; + clone->NumNativeParameters = prog->NumNativeParameters; + clone->NumNativeAttributes = prog->NumNativeAttributes; + clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; + clone->NumAluInstructions = prog->NumAluInstructions; + clone->NumTexInstructions = prog->NumTexInstructions; + clone->NumTexIndirections = prog->NumTexIndirections; + clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; + clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; + clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: { - /* 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_3V(value, ctx->Light.Light[ln].EyeDirection); - value[3] = ctx->Light.Light[ln]._CosCutoff; - return; - case STATE_HALF: - { - GLfloat eye_z[] = {0, 0, 1}; - - /* 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. - */ - 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; - } - } - 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 < 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 < 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: - { - 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; - } - } - 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; - } - } - case STATE_TEXENV_COLOR: - { - /* state[1] is the texture unit */ - const GLuint unit = (GLuint) state[1]; - COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); - } - 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.Start); - 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) { - /* Be sure inverse is up to date: - */ - _math_matrix_alloc_inv( (GLmatrix *) matrix ); - _math_matrix_analyse( (GLmatrix*) matrix ); - 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; - 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; - return; - case STATE_FRAGMENT_PROGRAM: - { - /* state[1] = {STATE_ENV, STATE_LOCAL} */ - /* state[2] = parameter index */ - const int idx = (int) state[2]; - switch (state[1]) { - case STATE_ENV: - COPY_4V(value, ctx->FragmentProgram.Parameters[idx]); - break; - case STATE_LOCAL: - COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]); - 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 */ - const int idx = (int) state[2]; - switch (state[1]) { - case STATE_ENV: - COPY_4V(value, ctx->VertexProgram.Parameters[idx]); - break; - case STATE_LOCAL: - COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]); - 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 _mesa_fetch_state"); - return; - } -} - - -/** - * Return a bit mask of the Mesa state flags under which a parameter's - * value might change. - */ -static GLuint 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; - default: - _mesa_problem(NULL, "unexpected int. state in make_state_flags()"); - return 0; - } - - default: - _mesa_problem(NULL, "unexpected state[0] in make_state_flags()"); - return 0; - } -} - - -static void -append(char *dst, const char *src) -{ - while (*dst) - dst++; - while (*src) - *dst++ = *src++; - *dst = 0; -} - - -static void -append_token(char *dst, enum state_index k) -{ - switch (k) { - case STATE_MATERIAL: - append(dst, "material."); - break; - case STATE_LIGHT: - append(dst, "light"); - break; - case STATE_LIGHTMODEL_AMBIENT: - append(dst, "lightmodel.ambient"); - break; - case STATE_LIGHTMODEL_SCENECOLOR: - break; - case STATE_LIGHTPROD: - append(dst, "lightprod"); - break; - case STATE_TEXGEN: - append(dst, "texgen"); - break; - case STATE_FOG_COLOR: - append(dst, "fog.color"); - break; - case STATE_FOG_PARAMS: - append(dst, "fog.params"); - break; - case STATE_CLIPPLANE: - append(dst, "clip"); - break; - case STATE_POINT_SIZE: - append(dst, "point.size"); - break; - case STATE_POINT_ATTENUATION: - append(dst, "point.attenuation"); - break; - case STATE_MATRIX: - append(dst, "matrix."); - break; - case STATE_MODELVIEW: - append(dst, "modelview"); - break; - case STATE_PROJECTION: - append(dst, "projection"); - break; - case STATE_MVP: - append(dst, "mvp"); - break; - case STATE_TEXTURE: - append(dst, "texture"); - break; - case STATE_PROGRAM: - append(dst, "program"); - break; - case STATE_MATRIX_INVERSE: - append(dst, ".inverse"); - break; - case STATE_MATRIX_TRANSPOSE: - append(dst, ".transpose"); - break; - case STATE_MATRIX_INVTRANS: - append(dst, ".invtrans"); - break; - case STATE_AMBIENT: - append(dst, "ambient"); - break; - case STATE_DIFFUSE: - append(dst, "diffuse"); - break; - case STATE_SPECULAR: - append(dst, "specular"); - break; - case STATE_EMISSION: - append(dst, "emission"); - break; - case STATE_SHININESS: - append(dst, "shininess"); - break; - case STATE_HALF: - append(dst, "half"); - break; - case STATE_POSITION: - append(dst, ".position"); - break; - case STATE_ATTENUATION: - append(dst, ".attenuation"); - break; - case STATE_SPOT_DIRECTION: - append(dst, ".spot.direction"); - break; - case STATE_TEXGEN_EYE_S: - append(dst, "eye.s"); - break; - case STATE_TEXGEN_EYE_T: - append(dst, "eye.t"); - break; - case STATE_TEXGEN_EYE_R: - append(dst, "eye.r"); - break; - case STATE_TEXGEN_EYE_Q: - append(dst, "eye.q"); - break; - case STATE_TEXGEN_OBJECT_S: - append(dst, "object.s"); - break; - case STATE_TEXGEN_OBJECT_T: - append(dst, "object.t"); - break; - case STATE_TEXGEN_OBJECT_R: - append(dst, "object.r"); - break; - case STATE_TEXGEN_OBJECT_Q: - append(dst, "object.q"); - break; - case STATE_TEXENV_COLOR: - append(dst, "texenv"); - break; - case STATE_DEPTH_RANGE: - append(dst, "depth.range"); - break; - case STATE_VERTEX_PROGRAM: - case STATE_FRAGMENT_PROGRAM: - break; - case STATE_ENV: - append(dst, "env"); - break; - case STATE_LOCAL: - append(dst, "local"); - break; - case STATE_INTERNAL: - case STATE_NORMAL_SCALE: - case STATE_POSITION_NORMALIZED: - append(dst, "(internal)"); - break; - default: - ; - } -} - -static void -append_face(char *dst, GLint face) -{ - if (face == 0) - append(dst, "front."); - else - append(dst, "back."); -} - -static void -append_index(char *dst, GLint index) -{ - char s[20]; - _mesa_sprintf(s, "[%d].", index); - append(dst, s); -} - -/** - * 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 str[1000] = ""; - char tmp[30]; - - append(str, "state."); - append_token(str, (enum state_index) state[0]); - - switch (state[0]) { - case STATE_MATERIAL: - append_face(str, state[1]); - 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, (enum state_index) state[2]); /* coefficients */ - break; - case STATE_LIGHTMODEL_AMBIENT: - append(str, "lightmodel.ambient"); - break; - case STATE_LIGHTMODEL_SCENECOLOR: - if (state[1] == 0) { - append(str, "lightmodel.front.scenecolor"); + const struct gl_vertex_program *vp + = (const struct gl_vertex_program *) prog; + struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; + vpc->IsPositionInvariant = vp->IsPositionInvariant; } - else { - append(str, "lightmodel.back.scenecolor"); - } - break; - case STATE_LIGHTPROD: - append_index(str, state[1]); /* light number [i]. */ - append_face(str, state[2]); - append_token(str, (enum state_index) state[3]); - break; - case STATE_TEXGEN: - append_index(str, state[1]); /* tex unit [i] */ - append_token(str, (enum state_index) state[2]); /* plane coef */ - break; - case STATE_TEXENV_COLOR: - append_index(str, state[1]); /* tex unit [i] */ - append(str, "color"); break; - case STATE_FOG_COLOR: - case STATE_FOG_PARAMS: - break; - case STATE_CLIPPLANE: - append_index(str, state[1]); /* plane [i] */ - append(str, "plane"); - break; - case STATE_POINT_SIZE: - case STATE_POINT_ATTENUATION: - break; - case STATE_MATRIX: + case GL_FRAGMENT_PROGRAM_ARB: { - /* 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 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 = (enum state_index) state[5]; - append_token(str, mat); - if (index) - append_index(str, index); - if (modifier) - append_token(str, modifier); - if (first == last) - _mesa_sprintf(tmp, ".row[%d]", first); - else - _mesa_sprintf(tmp, ".row[%d..%d]", first, last); - append(str, tmp); + const struct gl_fragment_program *fp + = (const struct gl_fragment_program *) prog; + struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; + fpc->FogOption = fp->FogOption; + fpc->UsesKill = fp->UsesKill; } break; - case STATE_DEPTH_RANGE: - break; - case STATE_FRAGMENT_PROGRAM: - case STATE_VERTEX_PROGRAM: - /* state[1] = {STATE_ENV, STATE_LOCAL} */ - /* state[2] = parameter index */ - 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"); - break; + _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); } - return _mesa_strdup(str); + return clone; } /** - * 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. + * Insert 'count' NOP instructions at 'start' in the given program. + * Adjust branch targets accordingly. */ -void -_mesa_load_state_parameters(GLcontext *ctx, - struct gl_program_parameter_list *paramList) +GLboolean +_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) { + const GLuint origLen = prog->NumInstructions; + const GLuint newLen = origLen + count; + struct prog_instruction *newInst; GLuint i; - if (!paramList) - return; - - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) { - _mesa_fetch_state(ctx, - paramList->Parameters[i].StateIndexes, - paramList->ParameterValues[i]); + /* adjust branches */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->BranchTarget > 0) { + if ((GLuint)inst->BranchTarget >= start) { + inst->BranchTarget += count; + } } } -} - -/** - * Initialize program instruction fields to defaults. - */ -void -_mesa_init_instruction(struct prog_instruction *inst) -{ - _mesa_bzero(inst, sizeof(struct prog_instruction)); - - inst->SrcReg[0].File = PROGRAM_UNDEFINED; - inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; - inst->SrcReg[1].File = PROGRAM_UNDEFINED; - inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; - inst->SrcReg[2].File = PROGRAM_UNDEFINED; - inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; - - inst->DstReg.File = PROGRAM_UNDEFINED; - inst->DstReg.WriteMask = WRITEMASK_XYZW; - inst->DstReg.CondMask = COND_TR; - inst->DstReg.CondSwizzle = SWIZZLE_NOOP; - - inst->SaturateMode = SATURATE_OFF; - inst->Precision = FLOAT32; -} + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + return GL_FALSE; + } + /* Copy 'start' instructions into new instruction buffer */ + _mesa_copy_instructions(newInst, prog->Instructions, start); -/** - * 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)); -} + /* init the new instructions */ + _mesa_init_instructions(newInst + start, count); + /* Copy the remaining/tail instructions to new inst buffer */ + _mesa_copy_instructions(newInst + start + count, + prog->Instructions + start, + origLen - start); -/** - * 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 - * \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; + /* free old instructions */ + _mesa_free_instructions(prog->Instructions, origLen); - newInst = (struct prog_instruction *) - _mesa_realloc(oldInst, - numOldInst * sizeof(struct prog_instruction), - numNewInst * sizeof(struct prog_instruction)); + /* install new instructions */ + prog->Instructions = newInst; + prog->NumInstructions = newLen; - return newInst; + return GL_TRUE; } /** - * Basic info about each instruction - */ -struct instruction_info -{ - enum prog_opcode Opcode; - const char *Name; - GLuint NumSrcRegs; -}; - -/** - * Instruction info - * \note Opcode should equal array index! - */ -static const struct instruction_info InstInfo[MAX_OPCODE] = { - { OPCODE_ABS, "ABS", 1 }, - { OPCODE_ADD, "ADD", 2 }, - { OPCODE_ARA, "ARA", 1 }, - { OPCODE_ARL, "ARL", 1 }, - { OPCODE_ARL_NV, "ARL", 1 }, - { OPCODE_ARR, "ARL", 1 }, - { OPCODE_BRA, "BRA", 1 }, - { OPCODE_CAL, "CAL", 1 }, - { OPCODE_CMP, "CMP", 3 }, - { OPCODE_COS, "COS", 1 }, - { OPCODE_DDX, "DDX", 1 }, - { OPCODE_DDY, "DDY", 1 }, - { OPCODE_DP3, "DP3", 2 }, - { OPCODE_DP4, "DP4", 2 }, - { OPCODE_DPH, "DPH", 2 }, - { OPCODE_DST, "DST", 2 }, - { OPCODE_END, "END", 0 }, - { OPCODE_EX2, "EX2", 1 }, - { OPCODE_EXP, "EXP", 1 }, - { OPCODE_FLR, "FLR", 1 }, - { OPCODE_FRC, "FRC", 1 }, - { OPCODE_KIL, "KIL", 1 }, - { OPCODE_KIL_NV, "KIL", 0 }, - { OPCODE_LG2, "LG2", 1 }, - { OPCODE_LIT, "LIT", 1 }, - { OPCODE_LOG, "LOG", 1 }, - { OPCODE_LRP, "LRP", 3 }, - { OPCODE_MAD, "MAD", 3 }, - { OPCODE_MAX, "MAX", 2 }, - { OPCODE_MIN, "MIN", 2 }, - { OPCODE_MOV, "MOV", 1 }, - { OPCODE_MUL, "MUL", 2 }, - { OPCODE_PK2H, "PK2H", 1 }, - { OPCODE_PK2US, "PK2US", 1 }, - { OPCODE_PK4B, "PK4B", 1 }, - { OPCODE_PK4UB, "PK4UB", 1 }, - { OPCODE_POW, "POW", 2 }, - { OPCODE_POPA, "POPA", 0 }, - { OPCODE_PRINT, "PRINT", 1 }, - { OPCODE_PUSHA, "PUSHA", 0 }, - { OPCODE_RCC, "RCC", 1 }, - { OPCODE_RCP, "RCP", 1 }, - { OPCODE_RET, "RET", 1 }, - { OPCODE_RFL, "RFL", 1 }, - { OPCODE_RSQ, "RSQ", 1 }, - { OPCODE_SCS, "SCS", 1 }, - { OPCODE_SEQ, "SEQ", 2 }, - { OPCODE_SFL, "SFL", 0 }, - { OPCODE_SGE, "SGE", 2 }, - { OPCODE_SGT, "SGT", 2 }, - { OPCODE_SIN, "SIN", 1 }, - { OPCODE_SLE, "SLE", 2 }, - { OPCODE_SLT, "SLT", 2 }, - { OPCODE_SNE, "SNE", 2 }, - { OPCODE_SSG, "SSG", 1 }, - { OPCODE_STR, "STR", 0 }, - { OPCODE_SUB, "SUB", 2 }, - { OPCODE_SWZ, "SWZ", 1 }, - { OPCODE_TEX, "TEX", 1 }, - { OPCODE_TXB, "TXB", 1 }, - { OPCODE_TXD, "TXD", 3 }, - { OPCODE_TXL, "TXL", 1 }, - { OPCODE_TXP, "TXP", 1 }, - { OPCODE_TXP_NV, "TXP", 1 }, - { OPCODE_UP2H, "UP2H", 1 }, - { OPCODE_UP2US, "UP2US", 1 }, - { OPCODE_UP4B, "UP4B", 1 }, - { OPCODE_UP4UB, "UP4UB", 1 }, - { OPCODE_X2D, "X2D", 3 }, - { OPCODE_XPD, "XPD", 2 } -}; - - -/** - * Return the number of src registers for the given instruction/opcode. + * Search instructions for registers that match (oldFile, oldIndex), + * replacing them with (newFile, newIndex). */ -GLuint -_mesa_num_inst_src_regs(enum prog_opcode opcode) +static void +replace_registers(struct prog_instruction *inst, GLuint numInst, + GLuint oldFile, GLuint oldIndex, + GLuint newFile, GLuint newIndex) { - 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; + GLuint i, j; + for (i = 0; i < numInst; i++) { + /* src regs */ + for (j = 0; j < _mesa_num_inst_src_regs(inst->Opcode); j++) { + if (inst[i].SrcReg[j].File == oldFile && + inst[i].SrcReg[j].Index == oldIndex) { + inst[i].SrcReg[j].File = newFile; + inst[i].SrcReg[j].Index = newIndex; + } + } + /* dst reg */ + if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { + inst[i].DstReg.File = newFile; + inst[i].DstReg.Index = newIndex; } - } - _mesa_problem(NULL, "invalid opcode in _mesa_num_inst_src_regs"); - return 0; -} - - -/** - * Return string name for given program opcode. - */ -const char * -_mesa_opcode_string(enum prog_opcode opcode) -{ - ASSERT(opcode < MAX_OPCODE); - return InstInfo[opcode].Name; -} - -/** - * Return string name for given program/register file. - */ -static const char * -program_file_string(enum register_file f) -{ - switch (f) { - case PROGRAM_TEMPORARY: - return "TEMP"; - case PROGRAM_LOCAL_PARAM: - return "LOCAL"; - case PROGRAM_ENV_PARAM: - return "ENV"; - case PROGRAM_STATE_VAR: - return "STATE"; - case PROGRAM_INPUT: - return "INPUT"; - case PROGRAM_OUTPUT: - return "OUTPUT"; - case PROGRAM_NAMED_PARAM: - return "NAMED"; - case PROGRAM_CONSTANT: - return "CONST"; - case PROGRAM_WRITE_ONLY: - return "WRITE_ONLY"; - case PROGRAM_ADDRESS: - return "ADDR"; - default: - return "!unkown!"; } } /** - * Return a string representation of the given swizzle word. - * If extended is true, use extended (comma-separated) format. + * Search instructions for references to program parameters. When found, + * increment the parameter index by 'offset'. + * Used when combining programs. */ -static const char * -swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended) -{ - static const char swz[] = "xyzw01"; - static char s[20]; - GLuint i = 0; - - if (!extended && swizzle == SWIZZLE_NOOP && negateBase == 0) - return ""; /* no swizzle/negation */ - - if (!extended) - s[i++] = '.'; - - if (negateBase & 0x1) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 0)]; - - if (extended) { - s[i++] = ','; - } - - if (negateBase & 0x2) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 1)]; - - if (extended) { - s[i++] = ','; - } - - if (negateBase & 0x4) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 2)]; - - if (extended) { - s[i++] = ','; - } - - if (negateBase & 0x8) - s[i++] = '-'; - s[i++] = swz[GET_SWZ(swizzle, 3)]; - - s[i] = 0; - return s; -} - - -static const char * -writemask_string(GLuint writeMask) -{ - static char s[10]; - GLuint i = 0; - - if (writeMask == WRITEMASK_XYZW) - return ""; - - s[i++] = '.'; - if (writeMask & WRITEMASK_X) - s[i++] = 'x'; - if (writeMask & WRITEMASK_Y) - s[i++] = 'y'; - if (writeMask & WRITEMASK_Z) - s[i++] = 'z'; - if (writeMask & WRITEMASK_W) - s[i++] = 'w'; - - s[i] = 0; - return s; -} - static void -print_dst_reg(const struct prog_dst_register *dstReg) +adjust_param_indexes(struct prog_instruction *inst, GLuint numInst, + GLuint offset) { - _mesa_printf(" %s[%d]%s", - program_file_string((enum register_file) dstReg->File), - dstReg->Index, - writemask_string(dstReg->WriteMask)); -} - -static void -print_src_reg(const struct prog_src_register *srcReg) -{ - _mesa_printf("%s[%d]%s", - program_file_string((enum register_file) srcReg->File), - srcReg->Index, - swizzle_string(srcReg->Swizzle, - srcReg->NegateBase, GL_FALSE)); -} - - -/** - * Print a single vertex/fragment program instruction. - */ -void -_mesa_print_instruction(const struct prog_instruction *inst) -{ - switch (inst->Opcode) { - case OPCODE_PRINT: - _mesa_printf("PRINT '%s'", inst->Data); - if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { - _mesa_printf(", "); - _mesa_printf("%s[%d]%s", - 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)); - } - _mesa_printf(";\n"); - break; - case OPCODE_SWZ: - _mesa_printf("SWZ"); - if (inst->SaturateMode == SATURATE_ZERO_ONE) - _mesa_printf("_SAT"); - print_dst_reg(&inst->DstReg); - _mesa_printf("%s[%d], %s;\n", - 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)); - break; - case OPCODE_TEX: - case OPCODE_TXP: - case OPCODE_TXB: - _mesa_printf("%s", _mesa_opcode_string(inst->Opcode)); - if (inst->SaturateMode == SATURATE_ZERO_ONE) - _mesa_printf("_SAT"); - _mesa_printf(" "); - print_dst_reg(&inst->DstReg); - _mesa_printf(", "); - print_src_reg(&inst->SrcReg[0]); - _mesa_printf(", texture[%d], ", inst->TexSrcUnit); - switch (inst->TexSrcTarget) { - case TEXTURE_1D_INDEX: _mesa_printf("1D"); break; - case TEXTURE_2D_INDEX: _mesa_printf("2D"); break; - case TEXTURE_3D_INDEX: _mesa_printf("3D"); break; - case TEXTURE_CUBE_INDEX: _mesa_printf("CUBE"); break; - case TEXTURE_RECT_INDEX: _mesa_printf("RECT"); break; - default: - ; - } - _mesa_printf("\n"); - break; - case OPCODE_ARL: - _mesa_printf("ARL addr.x, "); - print_src_reg(&inst->SrcReg[0]); - _mesa_printf(";\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->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(", "); + GLuint i, j; + for (i = 0; i < numInst; i++) { + for (j = 0; j < _mesa_num_inst_src_regs(inst->Opcode); j++) { + GLuint f = inst[i].SrcReg[j].File; + if (f == PROGRAM_CONSTANT || + f == PROGRAM_UNIFORM || + f == PROGRAM_STATE_VAR) { + inst[i].SrcReg[j].Index += offset; } - - _mesa_printf(";\n"); } } } /** - * Print a vertx/fragment program to stdout. - * XXX this function could be greatly improved. + * Combine two programs into one. Fix instructions so the outputs of + * the first program go to the inputs of the second program. */ -void -_mesa_print_program(const struct gl_program *prog) +struct gl_program * +_mesa_combine_programs(GLcontext *ctx, + const struct gl_program *progA, + const struct gl_program *progB) { + struct prog_instruction *newInst; + struct gl_program *newProg; + const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ + const GLuint lenB = progB->NumInstructions; + const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); + const GLuint newLength = lenA + lenB; + GLbitfield inputsB; GLuint i; - for (i = 0; i < prog->NumInstructions; i++) { - _mesa_printf("%3d: ", i); - _mesa_print_instruction(prog->Instructions + i); - } -} + ASSERT(progA->Target == progB->Target); -/** - * Print all of a program's parameters. - */ -void -_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog) -{ - GLint i; - - _mesa_printf("NumInstructions=%d\n", prog->NumInstructions); - _mesa_printf("NumTemporaries=%d\n", prog->NumTemporaries); - _mesa_printf("NumParameters=%d\n", prog->NumParameters); - _mesa_printf("NumAttributes=%d\n", prog->NumAttributes); - _mesa_printf("NumAddressRegs=%d\n", prog->NumAddressRegs); - - _mesa_load_state_parameters(ctx, prog->Parameters); - -#if 0 - _mesa_printf("Local Params:\n"); - for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ - const GLfloat *p = prog->LocalParams[i]; - _mesa_printf("%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); - } -#endif - - for (i = 0; i < prog->Parameters->NumParameters; 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 */ -/**********************************************************************/ - - -/** - * Bind a program (make it current) - * \note Called from the GL API dispatcher by both glBindProgramNV - * and glBindProgramARB. - */ -void GLAPIENTRY -_mesa_BindProgram(GLenum target, GLuint id) -{ - struct gl_program *curProg, *newProg; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); + newInst = _mesa_alloc_instructions(newLength); + if (!newInst) + return GL_FALSE; - /* Error-check target and get curProg */ - if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */ - (ctx->Extensions.NV_vertex_program || - ctx->Extensions.ARB_vertex_program)) { - curProg = &ctx->VertexProgram.Current->Base; - } - else if ((target == GL_FRAGMENT_PROGRAM_NV - && ctx->Extensions.NV_fragment_program) || - (target == GL_FRAGMENT_PROGRAM_ARB - && ctx->Extensions.ARB_fragment_program)) { - curProg = &ctx->FragmentProgram.Current->Base; + _mesa_copy_instructions(newInst, progA->Instructions, lenA); + _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); + + /* adjust branch / instruction addresses for B's instructions */ + for (i = 0; i < lenB; i++) { + newInst[lenA + i].BranchTarget += lenA; + } + + newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); + newProg->Instructions = newInst; + newProg->NumInstructions = newLength; + + if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { + struct gl_fragment_program *fprogA, *fprogB, *newFprog; + GLbitfield progB_inputsRead = progB->InputsRead; + GLint progB_colorFile, progB_colorIndex; + + fprogA = (struct gl_fragment_program *) progA; + fprogB = (struct gl_fragment_program *) progB; + newFprog = (struct gl_fragment_program *) newProg; + + newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; + + /* We'll do a search and replace for instances + * of progB_colorFile/progB_colorIndex below... + */ + progB_colorFile = PROGRAM_INPUT; + progB_colorIndex = FRAG_ATTRIB_COL0; + + /* + * The fragment program may get color from a state var rather than + * a fragment input (vertex output) if it's constant. + * See the texenvprogram.c code. + * So, search the program's parameter list now to see if the program + * gets color from a state var instead of a conventional fragment + * input register. + */ + for (i = 0; i < progB->Parameters->NumParameters; i++) { + struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; + if (p->Type == PROGRAM_STATE_VAR && + p->StateIndexes[0] == STATE_INTERNAL && + p->StateIndexes[1] == STATE_CURRENT_ATTRIB && + p->StateIndexes[2] == VERT_ATTRIB_COLOR0) { + progB_inputsRead |= FRAG_BIT_COL0; + progB_colorFile = PROGRAM_STATE_VAR; + progB_colorIndex = i; + break; + } + } + + /* Connect color outputs of fprogA to color inputs of fprogB, via a + * new temporary register. + */ + if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) && + (progB_inputsRead & FRAG_BIT_COL0)) { + GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY); + if (tempReg < 0) { + _mesa_problem(ctx, "No free temp regs found in " + "_mesa_combine_programs(), using 31"); + tempReg = 31; + } + /* replace writes to result.color[0] with tempReg */ + replace_registers(newInst, lenA, + PROGRAM_OUTPUT, FRAG_RESULT_COLR, + PROGRAM_TEMPORARY, tempReg); + /* replace reads from the input color with tempReg */ + replace_registers(newInst + lenA, lenB, + progB_colorFile, progB_colorIndex, /* search for */ + PROGRAM_TEMPORARY, tempReg /* replace with */ ); + } + + /* compute combined program's InputsRead */ + inputsB = progB_inputsRead; + if (progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) { + inputsB &= ~(1 << FRAG_ATTRIB_COL0); + } + newProg->InputsRead = progA->InputsRead | inputsB; + newProg->OutputsWritten = progB->OutputsWritten; + newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; } else { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); - return; + /* vertex program */ + assert(0); /* XXX todo */ } /* - * 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. + * Merge parameters (uniforms, constants, etc) */ - if (id == 0) { - /* Bind a default program */ - newProg = NULL; - if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */ - newProg = ctx->Shared->DefaultVertexProgram; - else - newProg = ctx->Shared->DefaultFragmentProgram; - } - else { - /* Bind a user program */ - newProg = _mesa_lookup_program(ctx, id); - if (!newProg || newProg == &_mesa_DummyProgram) { - /* allocate a new program now */ - newProg = ctx->Driver.NewProgram(ctx, target, id); - if (!newProg) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); - return; - } - _mesa_HashInsert(ctx->Shared->Programs, id, newProg); - } - else if (!compatible_program_targets(newProg->Target, target)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindProgramNV/ARB(target mismatch)"); - return; - } - } + newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, + progB->Parameters); - /** All error checking is complete now **/ + adjust_param_indexes(newInst + lenA, lenB, numParamsA); - 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 */ - ctx->VertexProgram.Current = (struct gl_vertex_program *) newProg; - } - 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 (ctx->Driver.BindProgram) - ctx->Driver.BindProgram(ctx, target, newProg); -} - - -/** - * Delete a list of programs. - * \note Not compiled into display lists. - * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. - */ -void GLAPIENTRY -_mesa_DeletePrograms(GLsizei n, const GLuint *ids) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (n < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); - return; - } - - for (i = 0; i < n; i++) { - if (ids[i] != 0) { - struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); - if (prog == &_mesa_DummyProgram) { - _mesa_HashRemove(ctx->Shared->Programs, ids[i]); - } - else if (prog) { - /* Unbind program if necessary */ - 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]) { - /* unbind this currently bound program */ - _mesa_BindProgram(prog->Target, 0); - } - } - else if (prog->Target == GL_FRAGMENT_PROGRAM_NV || - prog->Target == GL_FRAGMENT_PROGRAM_ARB) { - if (ctx->FragmentProgram.Current && - ctx->FragmentProgram.Current->Base.Id == ids[i]) { - /* unbind this currently bound program */ - _mesa_BindProgram(prog->Target, 0); - } - } - else { - _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); - } - } - } - } + return newProg; } -/** - * Generate a list of new program identifiers. - * \note Not compiled into display lists. - * \note Called by both glGenProgramsNV and glGenProgramsARB. - */ -void GLAPIENTRY -_mesa_GenPrograms(GLsizei n, GLuint *ids) -{ - GLuint first; - GLuint i; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); - return; - } - - if (!ids) - return; - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); - - /* Insert pointer to dummy program as placeholder */ - for (i = 0; i < (GLuint) n; i++) { - _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram); - } - - /* Return the program names */ - for (i = 0; i < (GLuint) n; i++) { - ids[i] = first + i; - } -} /** - * Determine if id names a vertex or fragment program. - * \note Not compiled into display lists. - * \note Called from both glIsProgramNV and glIsProgramARB. - * \param id is the program identifier - * \return GL_TRUE if id is a program, else GL_FALSE. + * Scan the given program to find a free register of the given type. + * \param regFile - PROGRAM_INPUT, PROGRAM_OUTPUT or PROGRAM_TEMPORARY */ -GLboolean GLAPIENTRY -_mesa_IsProgram(GLuint id) +GLint +_mesa_find_free_register(const struct gl_program *prog, GLuint regFile) { - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - if (id == 0) - return GL_FALSE; - - if (_mesa_lookup_program(ctx, id)) - return GL_TRUE; - else - return GL_FALSE; -} - + GLboolean used[MAX_PROGRAM_TEMPS]; + GLuint i, k; + assert(regFile == PROGRAM_INPUT || + regFile == PROGRAM_OUTPUT || + regFile == PROGRAM_TEMPORARY); -/**********************************************************************/ -/* GL_MESA_program_debug extension */ -/**********************************************************************/ + _mesa_memset(used, 0, sizeof(used)); + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); -/* XXX temporary */ -GLAPI void GLAPIENTRY -glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback, - GLvoid *data) -{ - _mesa_ProgramCallbackMESA(target, callback, data); -} - - -void -_mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback, - GLvoid *data) -{ - GET_CURRENT_CONTEXT(ctx); - - switch (target) { - case GL_FRAGMENT_PROGRAM_ARB: - if (!ctx->Extensions.ARB_fragment_program) { - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)"); - return; - } - ctx->FragmentProgram.Callback = callback; - ctx->FragmentProgram.CallbackData = data; - break; - case GL_FRAGMENT_PROGRAM_NV: - if (!ctx->Extensions.NV_fragment_program) { - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)"); - return; + for (k = 0; k < n; k++) { + if (inst->SrcReg[k].File == regFile) { + used[inst->SrcReg[k].Index] = GL_TRUE; } - ctx->FragmentProgram.Callback = callback; - ctx->FragmentProgram.CallbackData = data; - break; - 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, "glProgramCallbackMESA(target)"); - return; - } - ctx->VertexProgram.Callback = callback; - ctx->VertexProgram.CallbackData = data; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)"); - return; - } -} - - -/* XXX temporary */ -GLAPI void GLAPIENTRY -glGetProgramRegisterfvMESA(GLenum target, - GLsizei len, const GLubyte *registerName, - GLfloat *v) -{ - _mesa_GetProgramRegisterfvMESA(target, len, registerName, v); -} - - -void -_mesa_GetProgramRegisterfvMESA(GLenum target, - GLsizei len, const GLubyte *registerName, - GLfloat *v) -{ - char reg[1000]; - GET_CURRENT_CONTEXT(ctx); - - /* We _should_ be inside glBegin/glEnd */ -#if 0 - if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA"); - return; + } } -#endif - - /* make null-terminated copy of registerName */ - len = MIN2((unsigned int) len, sizeof(reg) - 1); - _mesa_memcpy(reg, registerName, len); - reg[len] = 0; - - switch (target) { - 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(target)"); - return; - } - if (!ctx->VertexProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetProgramRegisterfvMESA"); - return; - } - /* GL_NV_vertex_program */ - if (reg[0] == 'R') { - /* Temp register */ - GLint i = _mesa_atoi(reg + 1); - if (i >= (GLint)ctx->Const.VertexProgram.MaxTemps) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - COPY_4V(v, ctx->VertexProgram.Temporaries[i]); - } - else if (reg[0] == 'v' && reg[1] == '[') { - /* Vertex Input attribute */ - GLuint i; - for (i = 0; i < ctx->Const.VertexProgram.MaxAttribs; i++) { - const char *name = _mesa_nv_vertex_input_register_name(i); - char number[10]; - _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]); - return; - } - } - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - else if (reg[0] == 'o' && reg[1] == '[') { - /* Vertex output attribute */ - } - /* GL_ARB_vertex_program */ - else if (_mesa_strncmp(reg, "vertex.", 7) == 0) { - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - if (!ctx->Extensions.ARB_fragment_program) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetProgramRegisterfvMESA(target)"); - return; - } - if (!ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetProgramRegisterfvMESA"); - return; - } - /* XXX to do */ - break; - case GL_FRAGMENT_PROGRAM_NV: - if (!ctx->Extensions.NV_fragment_program) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetProgramRegisterfvMESA(target)"); - return; - } - if (!ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetProgramRegisterfvMESA"); - return; - } - if (reg[0] == 'R') { - /* Temp register */ - GLint i = _mesa_atoi(reg + 1); - if (i >= (GLint)ctx->Const.FragmentProgram.MaxTemps) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]); - } - else if (reg[0] == 'f' && reg[1] == '[') { - /* Fragment input attribute */ - GLuint i; - 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]); - return; - } - } - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - else if (_mesa_strcmp(reg, "o[COLR]") == 0) { - /* Fragment output color */ - COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLR]); - } - else if (_mesa_strcmp(reg, "o[COLH]") == 0) { - /* Fragment output color */ - COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLH]); - } - else if (_mesa_strcmp(reg, "o[DEPR]") == 0) { - /* Fragment output depth */ - COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_DEPR]); - } - else { - /* try user-defined identifiers */ - const GLfloat *value = _mesa_lookup_parameter_value( - ctx->FragmentProgram.Current->Base.Parameters, -1, reg); - if (value) { - COPY_4V(v, value); - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetProgramRegisterfvMESA(registerName)"); - return; - } - } - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetProgramRegisterfvMESA(target)"); - return; + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + if (!used[i]) + return i; } + return -1; }