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