prototype _mesa_init_ati_fragment_shader()
[profile/ivi/mesa.git] / src / mesa / shader / program.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.2
4  *
5  * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 /**
26  * \file program.c
27  * Vertex and fragment program support functions.
28  * \author Brian Paul
29  */
30
31
32 #include "glheader.h"
33 #include "context.h"
34 #include "hash.h"
35 #include "imports.h"
36 #include "macros.h"
37 #include "mtypes.h"
38 #include "program.h"
39 #include "nvfragparse.h"
40 #include "nvfragprog.h"
41 #include "nvvertparse.h"
42 #include "nvvertprog.h"
43
44
45 /**********************************************************************/
46 /* Utility functions                                                  */
47 /**********************************************************************/
48
49
50 /* A pointer to this dummy program is put into the hash table when
51  * glGenPrograms is called.
52  */
53 struct program _mesa_DummyProgram;
54
55
56 /**
57  * Init context's vertex/fragment program state
58  */
59 void
60 _mesa_init_program(GLcontext *ctx)
61 {
62    GLuint i;
63
64    ctx->Program.ErrorPos = -1;
65    ctx->Program.ErrorString = _mesa_strdup("");
66
67 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
68    ctx->VertexProgram.Enabled = GL_FALSE;
69    ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
70    ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
71    ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram;
72    assert(ctx->VertexProgram.Current);
73    ctx->VertexProgram.Current->Base.RefCount++;
74    for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
75       ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
76       ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
77    }
78 #endif
79
80 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
81    ctx->FragmentProgram.Enabled = GL_FALSE;
82    ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram;
83    assert(ctx->FragmentProgram.Current);
84    ctx->FragmentProgram.Current->Base.RefCount++;
85 #endif
86
87 #if FEATURE_ATI_fragment_shader
88    ctx->ATIFragmentShader.Enabled = GL_FALSE;
89    ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
90    assert(ctx->ATIFragmentShader.Current);
91    ctx->ATIFragmentShader.Current->Base.RefCount++;
92 #endif
93 }
94
95
96 /**
97  * Free a context's vertex/fragment program state
98  */
99 void
100 _mesa_free_program_data(GLcontext *ctx)
101 {
102 #if FEATURE_NV_vertex_program
103    if (ctx->VertexProgram.Current) {
104       ctx->VertexProgram.Current->Base.RefCount--;
105       if (ctx->VertexProgram.Current->Base.RefCount <= 0)
106          ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
107    }
108 #endif
109 #if FEATURE_NV_fragment_program
110    if (ctx->FragmentProgram.Current) {
111       ctx->FragmentProgram.Current->Base.RefCount--;
112       if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
113          ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
114    }
115 #endif
116 #if FEATURE_ATI_fragment_shader
117    if (ctx->ATIFragmentShader.Current) {
118       ctx->ATIFragmentShader.Current->Base.RefCount--;
119       if (ctx->ATIFragmentShader.Current->Base.RefCount <= 0)
120         ctx->Driver.DeleteProgram(ctx, &(ctx->ATIFragmentShader.Current->Base));
121    }
122 #endif
123    _mesa_free((void *) ctx->Program.ErrorString);
124 }
125
126
127
128
129 /**
130  * Set the vertex/fragment program error state (position and error string).
131  * This is generally called from within the parsers.
132  */
133 void
134 _mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
135 {
136    ctx->Program.ErrorPos = pos;
137    _mesa_free((void *) ctx->Program.ErrorString);
138    if (!string)
139       string = "";
140    ctx->Program.ErrorString = _mesa_strdup(string);
141 }
142
143
144 /**
145  * Find the line number and column for 'pos' within 'string'.
146  * Return a copy of the line which contains 'pos'.  Free the line with
147  * _mesa_free().
148  * \param string  the program string
149  * \param pos     the position within the string
150  * \param line    returns the line number corresponding to 'pos'.
151  * \param col     returns the column number corresponding to 'pos'.
152  * \return copy of the line containing 'pos'.
153  */
154 const GLubyte *
155 _mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
156                        GLint *line, GLint *col)
157 {
158    const GLubyte *lineStart = string;
159    const GLubyte *p = string;
160    GLubyte *s;
161    int len;
162
163    *line = 1;
164
165    while (p != pos) {
166       if (*p == (GLubyte) '\n') {
167          (*line)++;
168          lineStart = p + 1;
169       }
170       p++;
171    }
172
173    *col = (pos - lineStart) + 1;
174
175    /* return copy of this line */
176    while (*p != 0 && *p != '\n')
177       p++;
178    len = p - lineStart;
179    s = (GLubyte *) _mesa_malloc(len + 1);
180    _mesa_memcpy(s, lineStart, len);
181    s[len] = 0;
182
183    return s;
184 }
185
186
187 /**
188  * Initialize a new vertex/fragment program object.
189  */
190 static struct program *
191 _mesa_init_program_struct( GLcontext *ctx, struct program *prog,
192                            GLenum target, GLuint id)
193 {
194    (void) ctx;
195    if (prog) {
196       prog->Id = id;
197       prog->Target = target;
198       prog->Resident = GL_TRUE;
199       prog->RefCount = 1;
200    }
201
202    return prog;
203 }
204
205
206 /**
207  * Initialize a new fragment program object.
208  */
209 struct program *
210 _mesa_init_fragment_program( GLcontext *ctx, struct fragment_program *prog,
211                              GLenum target, GLuint id)
212 {
213    if (prog) 
214       return _mesa_init_program_struct( ctx, &prog->Base, target, id );
215    else
216       return NULL;
217 }
218
219
220 /**
221  * Initialize a new vertex program object.
222  */
223 struct program *
224 _mesa_init_vertex_program( GLcontext *ctx, struct vertex_program *prog,
225                            GLenum target, GLuint id)
226 {
227    if (prog) 
228       return _mesa_init_program_struct( ctx, &prog->Base, target, id );
229    else
230       return NULL;
231 }
232
233 /**
234  * Initialize a new ATI fragment shader object.
235  */
236 struct program *
237 _mesa_init_ati_fragment_shader( GLcontext *ctx,
238                                 struct ati_fragment_shader *prog,
239                                 GLenum target, GLuint id )
240 {
241    if (prog) 
242       return _mesa_init_program_struct( ctx, &prog->Base, target, id );
243    else
244       return NULL;
245 }
246
247
248
249 /**
250  * Allocate and initialize a new fragment/vertex program object but
251  * don't put it into the program hash table.  Called via
252  * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
253  * device driver function to implement OO deriviation with additional
254  * types not understood by this function.
255  * 
256  * \param ctx  context
257  * \param id   program id/number
258  * \param target  program target/type
259  * \return  pointer to new program object
260  */
261 struct program *
262 _mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
263 {
264    switch (target) {
265    case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
266       return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program),
267                                         target, id );
268    case GL_FRAGMENT_PROGRAM_NV:
269    case GL_FRAGMENT_PROGRAM_ARB:
270       return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program),
271                                           target, id );
272    case GL_FRAGMENT_SHADER_ATI:
273       return _mesa_init_ati_fragment_shader( ctx, CALLOC_STRUCT(ati_fragment_shader),
274                                           target, id );
275
276    default:
277       _mesa_problem(ctx, "bad target in _mesa_new_program");
278       return NULL;
279    }
280 }
281
282
283 /**
284  * Delete a program and remove it from the hash table, ignoring the
285  * reference count.
286  * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
287  * by a device driver function.
288  */
289 void
290 _mesa_delete_program(GLcontext *ctx, struct program *prog)
291 {
292    (void) ctx;
293    ASSERT(prog);
294
295    if (prog->String)
296       _mesa_free(prog->String);
297    if (prog->Target == GL_VERTEX_PROGRAM_NV ||
298        prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
299       struct vertex_program *vprog = (struct vertex_program *) prog;
300       if (vprog->Instructions) {
301          GLuint i;
302          for (i = 0; i < vprog->Base.NumInstructions; i++) {
303             if (vprog->Instructions[i].Data)
304                _mesa_free(vprog->Instructions[i].Data);
305          }
306          _mesa_free(vprog->Instructions);
307       }
308       if (vprog->Parameters)
309          _mesa_free_parameter_list(vprog->Parameters);
310    }
311    else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
312             prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
313       struct fragment_program *fprog = (struct fragment_program *) prog;
314       if (fprog->Instructions) {
315          GLuint i;
316          for (i = 0; i < fprog->Base.NumInstructions; i++) {
317             if (fprog->Instructions[i].Data)
318                _mesa_free(fprog->Instructions[i].Data);
319          }
320          _mesa_free(fprog->Instructions);
321       }
322       if (fprog->Parameters)
323          _mesa_free_parameter_list(fprog->Parameters);
324    }
325    else if (prog->Target == GL_FRAGMENT_SHADER_ATI) {
326       struct ati_fragment_shader *atifs = (struct ati_fragment_shader *)prog;
327       if (atifs->Instructions)
328          _mesa_free(atifs->Instructions);
329    }
330
331    _mesa_free(prog);
332 }
333
334
335
336 /**********************************************************************/
337 /* Program parameter functions                                        */
338 /**********************************************************************/
339
340 struct program_parameter_list *
341 _mesa_new_parameter_list(void)
342 {
343    return (struct program_parameter_list *)
344       _mesa_calloc(sizeof(struct program_parameter_list));
345 }
346
347
348 /**
349  * Free a parameter list and all its parameters
350  */
351 void
352 _mesa_free_parameter_list(struct program_parameter_list *paramList)
353 {
354    _mesa_free_parameters(paramList);
355    _mesa_free(paramList);
356 }
357
358
359 /**
360  * Free all the parameters in the given list, but don't free the
361  * paramList structure itself.
362  */
363 void
364 _mesa_free_parameters(struct program_parameter_list *paramList)
365 {
366    GLuint i;
367    for (i = 0; i < paramList->NumParameters; i++) {
368       _mesa_free((void *) paramList->Parameters[i].Name);
369    }
370    _mesa_free(paramList->Parameters);
371    paramList->NumParameters = 0;
372    paramList->Parameters = NULL;
373 }
374
375
376 /**
377  * Helper function used by the functions below.
378  */
379 static GLint
380 add_parameter(struct program_parameter_list *paramList,
381               const char *name, const GLfloat values[4],
382               enum parameter_type type)
383 {
384    const GLuint n = paramList->NumParameters;
385
386    paramList->Parameters = (struct program_parameter *)
387       _mesa_realloc(paramList->Parameters,
388                     n * sizeof(struct program_parameter),
389                     (n + 1) * sizeof(struct program_parameter));
390    if (!paramList->Parameters) {
391       /* out of memory */
392       paramList->NumParameters = 0;
393       return -1;
394    }
395    else {
396       paramList->NumParameters = n + 1;
397       paramList->Parameters[n].Name = _mesa_strdup(name);
398       paramList->Parameters[n].Type = type;
399       if (values)
400          COPY_4V(paramList->Parameters[n].Values, values);
401       return (GLint) n;
402    }
403 }
404
405
406 /**
407  * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
408  * \return index of the new entry in the parameter list
409  */
410 GLint
411 _mesa_add_named_parameter(struct program_parameter_list *paramList,
412                           const char *name, const GLfloat values[4])
413 {
414    return add_parameter(paramList, name, values, NAMED_PARAMETER);
415 }
416
417
418 /**
419  * Add a new unnamed constant to the parameter list.
420  * \param paramList - the parameter list
421  * \param values - four float values
422  * \return index of the new parameter.
423  */
424 GLint
425 _mesa_add_named_constant(struct program_parameter_list *paramList,
426                          const char *name, const GLfloat values[4])
427 {
428    return add_parameter(paramList, name, values, CONSTANT);
429 }
430
431
432 /**
433  * Add a new unnamed constant to the parameter list.
434  * \param paramList - the parameter list
435  * \param values - four float values
436  * \return index of the new parameter.
437  */
438 GLint
439 _mesa_add_unnamed_constant(struct program_parameter_list *paramList,
440                            const GLfloat values[4])
441 {
442    /* generate a new dummy name */
443    static GLuint n = 0;
444    char name[20];
445    _mesa_sprintf(name, "constant%d", n);
446    n++;
447    /* store it */
448    return add_parameter(paramList, name, values, CONSTANT);
449 }
450
451
452 /**
453  * Add a new state reference to the parameter list.
454  * \param paramList - the parameter list
455  * \param state     - an array of 6 state tokens
456  *
457  * \return index of the new parameter.
458  */
459 GLint
460 _mesa_add_state_reference(struct program_parameter_list *paramList,
461                           GLint *stateTokens)
462 {
463    /* XXX Should we parse <stateString> here and produce the parameter's
464     * list of STATE_* tokens here, or in the parser?
465     */
466    GLint a, idx;
467
468    idx = add_parameter(paramList, "Some State", NULL, STATE);
469         
470    for (a=0; a<6; a++)
471       paramList->Parameters[idx].StateIndexes[a] = (enum state_index) stateTokens[a];
472
473    return idx;
474 }
475
476
477 /**
478  * Lookup a parameter value by name in the given parameter list.
479  * \return pointer to the float[4] values.
480  */
481 GLfloat *
482 _mesa_lookup_parameter_value(struct program_parameter_list *paramList,
483                              GLsizei nameLen, const char *name)
484 {
485    GLuint i;
486
487    if (!paramList)
488       return NULL;
489
490    if (nameLen == -1) {
491       /* name is null-terminated */
492       for (i = 0; i < paramList->NumParameters; i++) {
493          if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
494             return paramList->Parameters[i].Values;
495       }
496    }
497    else {
498       /* name is not null-terminated, use nameLen */
499       for (i = 0; i < paramList->NumParameters; i++) {
500          if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
501              && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
502             return paramList->Parameters[i].Values;
503       }
504    }
505    return NULL;
506 }
507
508
509 /**
510  * Lookup a parameter index by name in the given parameter list.
511  * \return index of parameter in the list.
512  */
513 GLint
514 _mesa_lookup_parameter_index(struct program_parameter_list *paramList,
515                              GLsizei nameLen, const char *name)
516 {
517    GLint i;
518
519    if (!paramList)
520       return -1;
521
522    if (nameLen == -1) {
523       /* name is null-terminated */
524       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
525          if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
526             return i;
527       }
528    }
529    else {
530       /* name is not null-terminated, use nameLen */
531       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
532          if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
533              && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
534             return i;
535       }
536    }
537    return -1;
538 }
539
540
541 /**
542  * Use the list of tokens in the state[] array to find global GL state
543  * and return it in <value>.  Usually, four values are returned in <value>
544  * but matrix queries may return as many as 16 values.
545  * This function is used for ARB vertex/fragment programs.
546  * The program parser will produce the state[] values.
547  */
548 static void
549 _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
550                   GLfloat *value)
551 {
552    switch (state[0]) {
553    case STATE_MATERIAL:
554       {
555          /* state[1] is either 0=front or 1=back side */
556          const GLuint face = (GLuint) state[1];
557          /* state[2] is the material attribute */
558          switch (state[2]) {
559          case STATE_AMBIENT:
560             if (face == 0)
561                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
562             else
563                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
564             return;
565          case STATE_DIFFUSE:
566             if (face == 0)
567                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
568             else
569                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
570             return;
571          case STATE_SPECULAR:
572             if (face == 0)
573                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
574             else
575                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
576             return;
577          case STATE_EMISSION:
578             if (face == 0)
579                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
580             else
581                COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
582             return;
583          case STATE_SHININESS:
584             if (face == 0)
585                value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
586             else
587                value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
588             value[1] = 0.0F;
589             value[2] = 0.0F;
590             value[3] = 1.0F;
591             return;
592          default:
593             _mesa_problem(ctx, "Invalid material state in fetch_state");
594             return;
595          }
596       }
597    case STATE_LIGHT:
598       {
599          /* state[1] is the light number */
600          const GLuint ln = (GLuint) state[1];
601          /* state[2] is the light attribute */
602          switch (state[2]) {
603          case STATE_AMBIENT:
604             COPY_4V(value, ctx->Light.Light[ln].Ambient);
605             return;
606          case STATE_DIFFUSE:
607             COPY_4V(value, ctx->Light.Light[ln].Diffuse);
608             return;
609          case STATE_SPECULAR:
610             COPY_4V(value, ctx->Light.Light[ln].Specular);
611             return;
612          case STATE_POSITION:
613             COPY_4V(value, ctx->Light.Light[ln].EyePosition);
614             return;
615          case STATE_ATTENUATION:
616             value[0] = ctx->Light.Light[ln].ConstantAttenuation;
617             value[1] = ctx->Light.Light[ln].LinearAttenuation;
618             value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
619             value[3] = ctx->Light.Light[ln].SpotExponent;
620             return;
621          case STATE_SPOT_DIRECTION:
622             COPY_4V(value, ctx->Light.Light[ln].EyeDirection);
623             return;
624          case STATE_HALF:
625             {
626                GLfloat eye_z[] = {0, 0, 1};
627                                         
628                /* Compute infinite half angle vector:
629                 *   half-vector = light_position + (0, 0, 1) 
630                 * and then normalize.  w = 0
631                                          *
632                                          * light.EyePosition.w should be 0 for infinite lights.
633                 */
634                                         ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
635                                         NORMALIZE_3FV(value);
636                                         value[3] = 0;
637             }                                             
638             return;
639          default:
640             _mesa_problem(ctx, "Invalid light state in fetch_state");
641             return;
642          }
643       }
644    case STATE_LIGHTMODEL_AMBIENT:
645       COPY_4V(value, ctx->Light.Model.Ambient);
646       return;
647    case STATE_LIGHTMODEL_SCENECOLOR:
648       if (state[1] == 0) {
649          /* front */
650          GLint i;
651          for (i = 0; i < 4; i++) {
652             value[i] = ctx->Light.Model.Ambient[i]
653                * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
654                + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
655          }
656       }
657       else {
658          /* back */
659          GLint i;
660          for (i = 0; i < 4; i++) {
661             value[i] = ctx->Light.Model.Ambient[i]
662                * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
663                + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
664          }
665       }
666       return;
667    case STATE_LIGHTPROD:
668       {
669          const GLuint ln = (GLuint) state[1];
670          const GLuint face = (GLuint) state[2];
671          GLint i;
672          ASSERT(face == 0 || face == 1);
673          switch (state[3]) {
674             case STATE_AMBIENT:
675                for (i = 0; i < 3; i++) {
676                   value[i] = ctx->Light.Light[ln].Ambient[i] *
677                      ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
678                }
679                /* [3] = material alpha */
680                value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
681                return;
682             case STATE_DIFFUSE:
683                for (i = 0; i < 3; i++) {
684                   value[i] = ctx->Light.Light[ln].Diffuse[i] *
685                      ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
686                }
687                /* [3] = material alpha */
688                value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
689                return;
690             case STATE_SPECULAR:
691                for (i = 0; i < 3; i++) {
692                   value[i] = ctx->Light.Light[ln].Specular[i] *
693                      ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
694                }
695                /* [3] = material alpha */
696                value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
697                return;
698             default:
699                _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
700                return;
701          }
702       }
703    case STATE_TEXGEN:
704       {
705          /* state[1] is the texture unit */
706          const GLuint unit = (GLuint) state[1];
707          /* state[2] is the texgen attribute */
708          switch (state[2]) {
709          case STATE_TEXGEN_EYE_S:
710             COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
711             return;
712          case STATE_TEXGEN_EYE_T:
713             COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
714             return;
715          case STATE_TEXGEN_EYE_R:
716             COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
717             return;
718          case STATE_TEXGEN_EYE_Q:
719             COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
720             return;
721          case STATE_TEXGEN_OBJECT_S:
722             COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
723             return;
724          case STATE_TEXGEN_OBJECT_T:
725             COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
726             return;
727          case STATE_TEXGEN_OBJECT_R:
728             COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
729             return;
730          case STATE_TEXGEN_OBJECT_Q:
731             COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
732             return;
733          default:
734             _mesa_problem(ctx, "Invalid texgen state in fetch_state");
735             return;
736          }
737       }
738    case STATE_TEXENV_COLOR:
739       {         
740          /* state[1] is the texture unit */
741          const GLuint unit = (GLuint) state[1];
742          COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
743       }                 
744       return;
745    case STATE_FOG_COLOR:
746       COPY_4V(value, ctx->Fog.Color);
747       return;
748    case STATE_FOG_PARAMS:
749       value[0] = ctx->Fog.Density;
750       value[1] = ctx->Fog.Start;
751       value[2] = ctx->Fog.End;
752       value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
753       return;
754    case STATE_CLIPPLANE:
755       {
756          const GLuint plane = (GLuint) state[1];
757          COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
758       }
759       return;
760    case STATE_POINT_SIZE:
761       value[0] = ctx->Point.Size;
762       value[1] = ctx->Point.MinSize;
763       value[2] = ctx->Point.MaxSize;
764       value[3] = ctx->Point.Threshold;
765       return;
766    case STATE_POINT_ATTENUATION:
767       value[0] = ctx->Point.Params[0];
768       value[1] = ctx->Point.Params[1];
769       value[2] = ctx->Point.Params[2];
770       value[3] = 1.0F;
771       return;
772    case STATE_MATRIX:
773       {
774          /* state[1] = modelview, projection, texture, etc. */
775          /* state[2] = which texture matrix or program matrix */
776          /* state[3] = first column to fetch */
777          /* state[4] = last column to fetch */
778          /* state[5] = transpose, inverse or invtrans */
779
780          const GLmatrix *matrix;
781          const enum state_index mat = state[1];
782          const GLuint index = (GLuint) state[2];
783          const GLuint first = (GLuint) state[3];
784          const GLuint last = (GLuint) state[4];
785          const enum state_index modifier = state[5];
786          const GLfloat *m;
787          GLuint row, i;
788          if (mat == STATE_MODELVIEW) {
789             matrix = ctx->ModelviewMatrixStack.Top;
790          }
791          else if (mat == STATE_PROJECTION) {
792             matrix = ctx->ProjectionMatrixStack.Top;
793          }
794          else if (mat == STATE_MVP) {
795             matrix = &ctx->_ModelProjectMatrix;
796          }
797          else if (mat == STATE_TEXTURE) {
798             matrix = ctx->TextureMatrixStack[index].Top;
799          }
800          else if (mat == STATE_PROGRAM) {
801             matrix = ctx->ProgramMatrixStack[index].Top;
802          }
803          else {
804             _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
805             return;
806          }
807          if (modifier == STATE_MATRIX_INVERSE ||
808              modifier == STATE_MATRIX_INVTRANS) {
809             /* XXX be sure inverse is up to date */
810             m = matrix->inv;
811          }
812          else {
813             m = matrix->m;
814          }
815          if (modifier == STATE_MATRIX_TRANSPOSE ||
816              modifier == STATE_MATRIX_INVTRANS) {
817             for (i = 0, row = first; row <= last; row++) {
818                value[i++] = m[row * 4 + 0];
819                value[i++] = m[row * 4 + 1];
820                value[i++] = m[row * 4 + 2];
821                value[i++] = m[row * 4 + 3];
822             }
823          }
824          else {
825             for (i = 0, row = first; row <= last; row++) {
826                value[i++] = m[row + 0];
827                value[i++] = m[row + 4];
828                value[i++] = m[row + 8];
829                value[i++] = m[row + 12];
830             }
831          }
832       }
833       return;
834    case STATE_DEPTH_RANGE:
835       value[0] = ctx->Viewport.Near;                     /* near       */
836       value[1] = ctx->Viewport.Far;                      /* far        */
837       value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
838       value[3] = 0;
839       return;
840    case STATE_FRAGMENT_PROGRAM:
841       {
842          /* state[1] = {STATE_ENV, STATE_LOCAL} */
843          /* state[2] = parameter index          */
844          const int idx = (int) state[2];
845          switch (state[1]) {
846             case STATE_ENV:
847                COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
848                break;
849             case STATE_LOCAL:
850                COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
851                break;
852             default:
853                _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
854                return;
855          }
856       }
857       return;
858                 
859    case STATE_VERTEX_PROGRAM:
860       {
861          /* state[1] = {STATE_ENV, STATE_LOCAL} */
862          /* state[2] = parameter index          */
863          const int idx = (int) state[2];
864          switch (state[1]) {
865             case STATE_ENV:
866                COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
867                break;
868             case STATE_LOCAL:
869                COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
870                break;
871             default:
872                _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
873                return;
874          }
875       }
876       return;
877    default:
878       _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
879       return;
880    }
881 }
882
883
884 /**
885  * Loop over all the parameters in a parameter list.  If the parameter
886  * is a GL state reference, look up the current value of that state
887  * variable and put it into the parameter's Value[4] array.
888  * This would be called at glBegin time when using a fragment program.
889  */
890 void
891 _mesa_load_state_parameters(GLcontext *ctx,
892                             struct program_parameter_list *paramList)
893 {
894    GLuint i;
895
896    if (!paramList)
897       return;
898
899    for (i = 0; i < paramList->NumParameters; i++) {
900       if (paramList->Parameters[i].Type == STATE) {
901          _mesa_fetch_state(ctx, paramList->Parameters[i].StateIndexes,
902                            paramList->Parameters[i].Values);
903       }
904    }
905 }
906
907
908
909 /**********************************************************************/
910 /* API functions                                                      */
911 /**********************************************************************/
912
913
914 /**
915  * Bind a program (make it current)
916  * \note Called from the GL API dispatcher by both glBindProgramNV
917  * and glBindProgramARB.
918  */
919 void GLAPIENTRY
920 _mesa_BindProgram(GLenum target, GLuint id)
921 {
922    struct program *prog;
923    GET_CURRENT_CONTEXT(ctx);
924    ASSERT_OUTSIDE_BEGIN_END(ctx);
925
926    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
927
928    if ((target == GL_VERTEX_PROGRAM_NV
929         && ctx->Extensions.NV_vertex_program) ||
930        (target == GL_VERTEX_PROGRAM_ARB
931         && ctx->Extensions.ARB_vertex_program)) {
932       /*** Vertex program binding ***/
933       struct vertex_program *curProg = ctx->VertexProgram.Current;
934       if (curProg->Base.Id == id) {
935          /* binding same program - no change */
936          return;
937       }
938       if (curProg->Base.Id != 0) {
939          /* decrement refcount on previously bound vertex program */
940          curProg->Base.RefCount--;
941          /* and delete if refcount goes below one */
942          if (curProg->Base.RefCount <= 0) {
943             ASSERT(curProg->Base.DeletePending);
944             ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
945             _mesa_HashRemove(ctx->Shared->Programs, id);
946          }
947       }
948    }
949    else if ((target == GL_FRAGMENT_PROGRAM_NV
950              && ctx->Extensions.NV_fragment_program) ||
951             (target == GL_FRAGMENT_PROGRAM_ARB
952              && ctx->Extensions.ARB_fragment_program)) {
953       /*** Fragment program binding ***/
954       struct fragment_program *curProg = ctx->FragmentProgram.Current;
955       if (curProg->Base.Id == id) {
956          /* binding same program - no change */
957          return;
958       }
959       if (curProg->Base.Id != 0) {
960          /* decrement refcount on previously bound fragment program */
961          curProg->Base.RefCount--;
962          /* and delete if refcount goes below one */
963          if (curProg->Base.RefCount <= 0) {
964             ASSERT(curProg->Base.DeletePending);
965             ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
966             _mesa_HashRemove(ctx->Shared->Programs, id);
967          }
968       }
969    }
970    else {
971       _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
972       return;
973    }
974
975    /* NOTE: binding to a non-existant program is not an error.
976     * That's supposed to be caught in glBegin.
977     */
978    if (id == 0) {
979       /* Bind default program */
980       prog = NULL;
981       if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
982          prog = ctx->Shared->DefaultVertexProgram;
983       else
984          prog = ctx->Shared->DefaultFragmentProgram;
985    }
986    else {
987       /* Bind user program */
988       prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
989       if (!prog || prog == &_mesa_DummyProgram) {
990          /* allocate a new program now */
991          prog = ctx->Driver.NewProgram(ctx, target, id);
992          if (!prog) {
993             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
994             return;
995          }
996          _mesa_HashInsert(ctx->Shared->Programs, id, prog);
997       }
998       else if (prog->Target != target) {
999          _mesa_error(ctx, GL_INVALID_OPERATION,
1000                      "glBindProgramNV/ARB(target mismatch)");
1001          return;
1002       }
1003    }
1004
1005    /* bind now */
1006    if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
1007       ctx->VertexProgram.Current = (struct vertex_program *) prog;
1008    }
1009    else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
1010       ctx->FragmentProgram.Current = (struct fragment_program *) prog;
1011    }
1012
1013    /* Never null pointers */
1014    ASSERT(ctx->VertexProgram.Current);
1015    ASSERT(ctx->FragmentProgram.Current);
1016
1017    if (prog)
1018       prog->RefCount++;
1019
1020    if (ctx->Driver.BindProgram)
1021       ctx->Driver.BindProgram(ctx, target, prog);
1022 }
1023
1024
1025 /**
1026  * Delete a list of programs.
1027  * \note Not compiled into display lists.
1028  * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
1029  */
1030 void GLAPIENTRY 
1031 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
1032 {
1033    GLint i;
1034    GET_CURRENT_CONTEXT(ctx);
1035    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1036
1037    if (n < 0) {
1038       _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
1039       return;
1040    }
1041
1042    for (i = 0; i < n; i++) {
1043       if (ids[i] != 0) {
1044          struct program *prog = (struct program *)
1045             _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
1046          if (prog == &_mesa_DummyProgram) {
1047             _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1048          }
1049          else if (prog) {
1050             /* Unbind program if necessary */
1051             if (prog->Target == GL_VERTEX_PROGRAM_NV ||
1052                 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
1053                if (ctx->VertexProgram.Current &&
1054                    ctx->VertexProgram.Current->Base.Id == ids[i]) {
1055                   /* unbind this currently bound program */
1056                   _mesa_BindProgram(prog->Target, 0);
1057                }
1058             }
1059             else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
1060                      prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
1061                if (ctx->FragmentProgram.Current &&
1062                    ctx->FragmentProgram.Current->Base.Id == ids[i]) {
1063                   /* unbind this currently bound program */
1064                   _mesa_BindProgram(prog->Target, 0);
1065                }
1066             }
1067             else {
1068                _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
1069                return;
1070             }
1071             /* Decrement reference count if not already marked for delete */
1072             if (!prog->DeletePending) {
1073                prog->DeletePending = GL_TRUE;
1074                prog->RefCount--;
1075             }
1076             if (prog->RefCount <= 0) {
1077                _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1078                ctx->Driver.DeleteProgram(ctx, prog);
1079             }
1080          }
1081       }
1082    }
1083 }
1084
1085
1086 /**
1087  * Generate a list of new program identifiers.
1088  * \note Not compiled into display lists.
1089  * \note Called by both glGenProgramsNV and glGenProgramsARB.
1090  */
1091 void GLAPIENTRY
1092 _mesa_GenPrograms(GLsizei n, GLuint *ids)
1093 {
1094    GLuint first;
1095    GLuint i;
1096    GET_CURRENT_CONTEXT(ctx);
1097    ASSERT_OUTSIDE_BEGIN_END(ctx);
1098
1099    if (n < 0) {
1100       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
1101       return;
1102    }
1103
1104    if (!ids)
1105       return;
1106
1107    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
1108
1109    /* Insert pointer to dummy program as placeholder */
1110    for (i = 0; i < (GLuint) n; i++) {
1111       _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
1112    }
1113
1114    /* Return the program names */
1115    for (i = 0; i < (GLuint) n; i++) {
1116       ids[i] = first + i;
1117    }
1118 }
1119
1120
1121 /**
1122  * Determine if id names a vertex or fragment program.
1123  * \note Not compiled into display lists.
1124  * \note Called from both glIsProgramNV and glIsProgramARB.
1125  * \param id is the program identifier
1126  * \return GL_TRUE if id is a program, else GL_FALSE.
1127  */
1128 GLboolean GLAPIENTRY
1129 _mesa_IsProgram(GLuint id)
1130 {
1131    GET_CURRENT_CONTEXT(ctx);
1132    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1133
1134    if (id == 0)
1135       return GL_FALSE;
1136
1137    if (_mesa_HashLookup(ctx->Shared->Programs, id))
1138       return GL_TRUE;
1139    else
1140       return GL_FALSE;
1141 }
1142
1143
1144
1145 /**********************************************************************/
1146 /* GL_MESA_program_debug extension                                    */
1147 /**********************************************************************/
1148
1149
1150 /* XXX temporary */
1151 void
1152 glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1153                       GLvoid *data)
1154 {
1155    _mesa_ProgramCallbackMESA(target, callback, data);
1156 }
1157
1158
1159 void
1160 _mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1161                           GLvoid *data)
1162 {
1163    GET_CURRENT_CONTEXT(ctx);
1164
1165    switch (target) {
1166       case GL_FRAGMENT_PROGRAM_ARB:
1167          if (!ctx->Extensions.ARB_fragment_program) {
1168             _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1169             return;
1170          }
1171          ctx->FragmentProgram.Callback = callback;
1172          ctx->FragmentProgram.CallbackData = data;
1173          break;
1174       case GL_FRAGMENT_PROGRAM_NV:
1175          if (!ctx->Extensions.NV_fragment_program) {
1176             _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1177             return;
1178          }
1179          ctx->FragmentProgram.Callback = callback;
1180          ctx->FragmentProgram.CallbackData = data;
1181          break;
1182       case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
1183          if (!ctx->Extensions.ARB_vertex_program &&
1184              !ctx->Extensions.NV_vertex_program) {
1185             _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1186             return;
1187          }
1188          ctx->VertexProgram.Callback = callback;
1189          ctx->VertexProgram.CallbackData = data;
1190          break;
1191       default:
1192          _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1193          return;
1194    }
1195 }
1196
1197
1198 /* XXX temporary */
1199 void
1200 glGetProgramRegisterfvMESA(GLenum target,
1201                            GLsizei len, const GLubyte *registerName,
1202                            GLfloat *v)
1203 {
1204    _mesa_GetProgramRegisterfvMESA(target, len, registerName, v);
1205 }
1206
1207
1208 void
1209 _mesa_GetProgramRegisterfvMESA(GLenum target,
1210                                GLsizei len, const GLubyte *registerName,
1211                                GLfloat *v)
1212 {
1213    char reg[1000];
1214    GET_CURRENT_CONTEXT(ctx);
1215
1216    /* We _should_ be inside glBegin/glEnd */
1217 #if 0
1218    if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
1219       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA");
1220       return;
1221    }
1222 #endif
1223
1224    /* make null-terminated copy of registerName */
1225    len = MIN2((unsigned int) len, sizeof(reg) - 1);
1226    _mesa_memcpy(reg, registerName, len);
1227    reg[len] = 0;
1228
1229    switch (target) {
1230       case GL_VERTEX_PROGRAM_NV:
1231          if (!ctx->Extensions.ARB_vertex_program &&
1232              !ctx->Extensions.NV_vertex_program) {
1233             _mesa_error(ctx, GL_INVALID_ENUM,
1234                         "glGetProgramRegisterfvMESA(target)");
1235             return;
1236          }
1237          if (!ctx->VertexProgram._Enabled) {
1238             _mesa_error(ctx, GL_INVALID_OPERATION,
1239                         "glGetProgramRegisterfvMESA");
1240             return;
1241          }
1242          /* GL_NV_vertex_program */
1243          if (reg[0] == 'R') {
1244             /* Temp register */
1245             GLint i = _mesa_atoi(reg + 1);
1246             if (i >= (GLint)ctx->Const.MaxVertexProgramTemps) {
1247                _mesa_error(ctx, GL_INVALID_VALUE,
1248                            "glGetProgramRegisterfvMESA(registerName)");
1249                return;
1250             }
1251             COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
1252          }
1253          else if (reg[0] == 'v' && reg[1] == '[') {
1254             /* Vertex Input attribute */
1255             GLuint i;
1256             for (i = 0; i < ctx->Const.MaxVertexProgramAttribs; i++) {
1257                const char *name = _mesa_nv_vertex_input_register_name(i);
1258                char number[10];
1259                sprintf(number, "%d", i);
1260                if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
1261                    _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
1262                   COPY_4V(v, ctx->VertexProgram.Inputs[i]);
1263                   return;
1264                }
1265             }
1266             _mesa_error(ctx, GL_INVALID_VALUE,
1267                         "glGetProgramRegisterfvMESA(registerName)");
1268             return;
1269          }
1270          else if (reg[0] == 'o' && reg[1] == '[') {
1271             /* Vertex output attribute */
1272          }
1273          /* GL_ARB_vertex_program */
1274          else if (_mesa_strncmp(reg, "vertex.", 7) == 0) {
1275
1276          }
1277          else {
1278             _mesa_error(ctx, GL_INVALID_VALUE,
1279                         "glGetProgramRegisterfvMESA(registerName)");
1280             return;
1281          }
1282          break;
1283       case GL_FRAGMENT_PROGRAM_ARB:
1284          if (!ctx->Extensions.ARB_fragment_program) {
1285             _mesa_error(ctx, GL_INVALID_ENUM,
1286                         "glGetProgramRegisterfvMESA(target)");
1287             return;
1288          }
1289          if (!ctx->FragmentProgram._Enabled) {
1290             _mesa_error(ctx, GL_INVALID_OPERATION,
1291                         "glGetProgramRegisterfvMESA");
1292             return;
1293          }
1294          /* XXX to do */
1295          break;
1296       case GL_FRAGMENT_PROGRAM_NV:
1297          if (!ctx->Extensions.NV_fragment_program) {
1298             _mesa_error(ctx, GL_INVALID_ENUM,
1299                         "glGetProgramRegisterfvMESA(target)");
1300             return;
1301          }
1302          if (!ctx->FragmentProgram._Enabled) {
1303             _mesa_error(ctx, GL_INVALID_OPERATION,
1304                         "glGetProgramRegisterfvMESA");
1305             return;
1306          }
1307          if (reg[0] == 'R') {
1308             /* Temp register */
1309             GLint i = _mesa_atoi(reg + 1);
1310             if (i >= (GLint)ctx->Const.MaxFragmentProgramTemps) {
1311                _mesa_error(ctx, GL_INVALID_VALUE,
1312                            "glGetProgramRegisterfvMESA(registerName)");
1313                return;
1314             }
1315             COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
1316          }
1317          else if (reg[0] == 'f' && reg[1] == '[') {
1318             /* Fragment input attribute */
1319             GLuint i;
1320             for (i = 0; i < ctx->Const.MaxFragmentProgramAttribs; i++) {
1321                const char *name = _mesa_nv_fragment_input_register_name(i);
1322                if (_mesa_strncmp(reg + 2, name, 4) == 0) {
1323                   COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
1324                   return;
1325                }
1326             }
1327             _mesa_error(ctx, GL_INVALID_VALUE,
1328                         "glGetProgramRegisterfvMESA(registerName)");
1329             return;
1330          }
1331          else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
1332             /* Fragment output color */
1333             COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLR]);
1334          }
1335          else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
1336             /* Fragment output color */
1337             COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLH]);
1338          }
1339          else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
1340             /* Fragment output depth */
1341             COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_DEPR]);
1342          }
1343          else {
1344             /* try user-defined identifiers */
1345             const GLfloat *value = _mesa_lookup_parameter_value(
1346                        ctx->FragmentProgram.Current->Parameters, -1, reg);
1347             if (value) {
1348                COPY_4V(v, value);
1349             }
1350             else {
1351                _mesa_error(ctx, GL_INVALID_VALUE,
1352                            "glGetProgramRegisterfvMESA(registerName)");
1353                return;
1354             }
1355          }
1356          break;
1357       default:
1358          _mesa_error(ctx, GL_INVALID_ENUM,
1359                      "glGetProgramRegisterfvMESA(target)");
1360          return;
1361    }
1362
1363 }