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