blob: 371500304f4d76176cd9f2d0513e931d0c7ecb67 [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul4d12a052006-08-23 23:10:14 +00003 * Version: 6.5.1
Michal Krol2861e732004-03-29 11:09:34 +00004 *
Brian Paul65a51c02006-05-24 03:30:31 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Michal Krol2861e732004-03-29 11:09:34 +00006 *
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"
Brian Paul7e807512005-11-05 17:10:45 +000040#include "program_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000041#include "nvvertparse.h"
Roland Scheideggerf519a772005-09-02 01:11:53 +000042#include "atifragshader.h"
Michal Krol2861e732004-03-29 11:09:34 +000043
44
Brian Paul7b98b402005-11-12 23:25:49 +000045static const char *
46make_state_string(const GLint stateTokens[6]);
47
Keith Whitwellec1ffd92005-11-22 12:12:17 +000048static GLuint
49make_state_flags(const GLint state[]);
50
Brian Paul7b98b402005-11-12 23:25:49 +000051
Michal Krol2861e732004-03-29 11:09:34 +000052/**********************************************************************/
53/* Utility functions */
54/**********************************************************************/
55
56
Brian Paul765f1a12004-09-14 22:28:27 +000057/* A pointer to this dummy program is put into the hash table when
58 * glGenPrograms is called.
59 */
Brian Paul122629f2006-07-20 16:49:57 +000060struct gl_program _mesa_DummyProgram;
Brian Paul765f1a12004-09-14 22:28:27 +000061
62
Michal Krol2861e732004-03-29 11:09:34 +000063/**
Brian Paul21841f02004-08-14 14:28:11 +000064 * Init context's vertex/fragment program state
Michal Krol2861e732004-03-29 11:09:34 +000065 */
66void
67_mesa_init_program(GLcontext *ctx)
68{
69 GLuint i;
70
71 ctx->Program.ErrorPos = -1;
72 ctx->Program.ErrorString = _mesa_strdup("");
73
74#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
75 ctx->VertexProgram.Enabled = GL_FALSE;
76 ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
77 ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
Brian Paul122629f2006-07-20 16:49:57 +000078 ctx->VertexProgram.Current = (struct gl_vertex_program *) ctx->Shared->DefaultVertexProgram;
Michal Krol2861e732004-03-29 11:09:34 +000079 assert(ctx->VertexProgram.Current);
80 ctx->VertexProgram.Current->Base.RefCount++;
81 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
82 ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
83 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
84 }
85#endif
86
87#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
88 ctx->FragmentProgram.Enabled = GL_FALSE;
Brian Paul122629f2006-07-20 16:49:57 +000089 ctx->FragmentProgram.Current = (struct gl_fragment_program *) ctx->Shared->DefaultFragmentProgram;
Michal Krol2861e732004-03-29 11:09:34 +000090 assert(ctx->FragmentProgram.Current);
91 ctx->FragmentProgram.Current->Base.RefCount++;
92#endif
Dave Airlie7f752fe2004-12-19 03:06:59 +000093
Brian Paul63d68302005-11-19 16:43:04 +000094 /* XXX probably move this stuff */
Dave Airlie7f752fe2004-12-19 03:06:59 +000095#if FEATURE_ATI_fragment_shader
96 ctx->ATIFragmentShader.Enabled = GL_FALSE;
97 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
98 assert(ctx->ATIFragmentShader.Current);
Brian Paul63d68302005-11-19 16:43:04 +000099 ctx->ATIFragmentShader.Current->RefCount++;
Dave Airlie7f752fe2004-12-19 03:06:59 +0000100#endif
Michal Krol2861e732004-03-29 11:09:34 +0000101}
102
103
104/**
Brian Paul21841f02004-08-14 14:28:11 +0000105 * Free a context's vertex/fragment program state
106 */
107void
108_mesa_free_program_data(GLcontext *ctx)
109{
Roland Scheidegger93da6732006-03-01 23:11:14 +0000110#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
Brian Paul21841f02004-08-14 14:28:11 +0000111 if (ctx->VertexProgram.Current) {
112 ctx->VertexProgram.Current->Base.RefCount--;
113 if (ctx->VertexProgram.Current->Base.RefCount <= 0)
114 ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
115 }
116#endif
Roland Scheidegger93da6732006-03-01 23:11:14 +0000117#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
Brian Paul21841f02004-08-14 14:28:11 +0000118 if (ctx->FragmentProgram.Current) {
119 ctx->FragmentProgram.Current->Base.RefCount--;
120 if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
121 ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
122 }
123#endif
Brian Paul63d68302005-11-19 16:43:04 +0000124 /* XXX probably move this stuff */
Dave Airlie7f752fe2004-12-19 03:06:59 +0000125#if FEATURE_ATI_fragment_shader
126 if (ctx->ATIFragmentShader.Current) {
Brian Paul63d68302005-11-19 16:43:04 +0000127 ctx->ATIFragmentShader.Current->RefCount--;
128 if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
129 _mesa_free(ctx->ATIFragmentShader.Current);
130 }
Dave Airlie7f752fe2004-12-19 03:06:59 +0000131 }
132#endif
Brian Paul21841f02004-08-14 14:28:11 +0000133 _mesa_free((void *) ctx->Program.ErrorString);
134}
135
136
137
138
139/**
Michal Krol2861e732004-03-29 11:09:34 +0000140 * Set the vertex/fragment program error state (position and error string).
141 * This is generally called from within the parsers.
142 */
143void
144_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
145{
146 ctx->Program.ErrorPos = pos;
147 _mesa_free((void *) ctx->Program.ErrorString);
148 if (!string)
149 string = "";
150 ctx->Program.ErrorString = _mesa_strdup(string);
151}
152
153
154/**
155 * Find the line number and column for 'pos' within 'string'.
156 * Return a copy of the line which contains 'pos'. Free the line with
157 * _mesa_free().
158 * \param string the program string
159 * \param pos the position within the string
160 * \param line returns the line number corresponding to 'pos'.
161 * \param col returns the column number corresponding to 'pos'.
162 * \return copy of the line containing 'pos'.
163 */
164const GLubyte *
165_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
166 GLint *line, GLint *col)
167{
168 const GLubyte *lineStart = string;
169 const GLubyte *p = string;
170 GLubyte *s;
171 int len;
172
173 *line = 1;
174
175 while (p != pos) {
176 if (*p == (GLubyte) '\n') {
177 (*line)++;
178 lineStart = p + 1;
179 }
180 p++;
181 }
182
183 *col = (pos - lineStart) + 1;
184
185 /* return copy of this line */
186 while (*p != 0 && *p != '\n')
187 p++;
188 len = p - lineStart;
189 s = (GLubyte *) _mesa_malloc(len + 1);
190 _mesa_memcpy(s, lineStart, len);
191 s[len] = 0;
192
193 return s;
194}
195
196
Brian Paul765f1a12004-09-14 22:28:27 +0000197/**
198 * Initialize a new vertex/fragment program object.
199 */
Brian Paul122629f2006-07-20 16:49:57 +0000200static struct gl_program *
201_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
Brian Paul765f1a12004-09-14 22:28:27 +0000202 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000203{
Brian Paula6c423d2004-08-25 15:59:48 +0000204 (void) ctx;
Michal Krol2861e732004-03-29 11:09:34 +0000205 if (prog) {
206 prog->Id = id;
207 prog->Target = target;
208 prog->Resident = GL_TRUE;
209 prog->RefCount = 1;
210 }
211
212 return prog;
213}
214
Brian Paul765f1a12004-09-14 22:28:27 +0000215
216/**
217 * Initialize a new fragment program object.
218 */
Brian Paul122629f2006-07-20 16:49:57 +0000219struct gl_program *
220_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog,
Brian Paul765f1a12004-09-14 22:28:27 +0000221 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000222{
223 if (prog)
224 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
225 else
226 return NULL;
227}
228
Brian Paul765f1a12004-09-14 22:28:27 +0000229
230/**
231 * Initialize a new vertex program object.
232 */
Brian Paul122629f2006-07-20 16:49:57 +0000233struct gl_program *
234_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
Brian Paul765f1a12004-09-14 22:28:27 +0000235 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000236{
237 if (prog)
238 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
239 else
240 return NULL;
241}
242
243
244/**
245 * Allocate and initialize a new fragment/vertex program object but
246 * don't put it into the program hash table. Called via
247 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
248 * device driver function to implement OO deriviation with additional
249 * types not understood by this function.
250 *
251 * \param ctx context
252 * \param id program id/number
253 * \param target program target/type
254 * \return pointer to new program object
255 */
Brian Paul122629f2006-07-20 16:49:57 +0000256struct gl_program *
Michal Krol2861e732004-03-29 11:09:34 +0000257_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
258{
259 switch (target) {
260 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
Brian Paul122629f2006-07-20 16:49:57 +0000261 return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
262 target, id );
Michal Krol2861e732004-03-29 11:09:34 +0000263 case GL_FRAGMENT_PROGRAM_NV:
264 case GL_FRAGMENT_PROGRAM_ARB:
Brian Paul122629f2006-07-20 16:49:57 +0000265 return _mesa_init_fragment_program(ctx,
266 CALLOC_STRUCT(gl_fragment_program),
267 target, id );
Michal Krol2861e732004-03-29 11:09:34 +0000268 default:
269 _mesa_problem(ctx, "bad target in _mesa_new_program");
270 return NULL;
271 }
272}
273
274
275/**
276 * Delete a program and remove it from the hash table, ignoring the
277 * reference count.
278 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
279 * by a device driver function.
280 */
281void
Brian Paul122629f2006-07-20 16:49:57 +0000282_mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
Michal Krol2861e732004-03-29 11:09:34 +0000283{
Brian Paula6c423d2004-08-25 15:59:48 +0000284 (void) ctx;
Michal Krol2861e732004-03-29 11:09:34 +0000285 ASSERT(prog);
286
287 if (prog->String)
288 _mesa_free(prog->String);
Brian Paulde997602005-11-12 17:53:14 +0000289
290 if (prog->Instructions) {
291 GLuint i;
292 for (i = 0; i < prog->NumInstructions; i++) {
293 if (prog->Instructions[i].Data)
294 _mesa_free(prog->Instructions[i].Data);
Brian Paul575700f2004-12-16 03:07:18 +0000295 }
Brian Paulde997602005-11-12 17:53:14 +0000296 _mesa_free(prog->Instructions);
Michal Krol2861e732004-03-29 11:09:34 +0000297 }
Brian Paulde997602005-11-12 17:53:14 +0000298
Brian Paul65a51c02006-05-24 03:30:31 +0000299 if (prog->Parameters) {
Brian Paulde997602005-11-12 17:53:14 +0000300 _mesa_free_parameter_list(prog->Parameters);
Brian Paul65a51c02006-05-24 03:30:31 +0000301 }
Brian Paulde997602005-11-12 17:53:14 +0000302
Michal Krol2861e732004-03-29 11:09:34 +0000303 _mesa_free(prog);
304}
305
306
Brian Paul4d12a052006-08-23 23:10:14 +0000307/**
308 * Return the gl_program object for a given ID.
309 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
310 * casts elsewhere.
311 */
312struct gl_program *
313_mesa_lookup_program(GLcontext *ctx, GLuint id)
314{
315 if (id)
316 return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
317 else
318 return NULL;
319}
320
Michal Krol2861e732004-03-29 11:09:34 +0000321
322/**********************************************************************/
323/* Program parameter functions */
324/**********************************************************************/
325
Brian Paul122629f2006-07-20 16:49:57 +0000326struct gl_program_parameter_list *
Michal Krol2861e732004-03-29 11:09:34 +0000327_mesa_new_parameter_list(void)
328{
Brian Paul122629f2006-07-20 16:49:57 +0000329 return (struct gl_program_parameter_list *)
330 _mesa_calloc(sizeof(struct gl_program_parameter_list));
Michal Krol2861e732004-03-29 11:09:34 +0000331}
332
333
334/**
335 * Free a parameter list and all its parameters
336 */
337void
Brian Paul122629f2006-07-20 16:49:57 +0000338_mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
Michal Krol2861e732004-03-29 11:09:34 +0000339{
Michal Krol2861e732004-03-29 11:09:34 +0000340 GLuint i;
341 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000342 if (paramList->Parameters[i].Name)
343 _mesa_free((void *) paramList->Parameters[i].Name);
Michal Krol2861e732004-03-29 11:09:34 +0000344 }
Brian Paul65a51c02006-05-24 03:30:31 +0000345 _mesa_free(paramList->Parameters);
346 if (paramList->ParameterValues)
347 _mesa_align_free(paramList->ParameterValues);
348 _mesa_free(paramList);
Michal Krol2861e732004-03-29 11:09:34 +0000349}
350
351
352/**
Brian Paul65a51c02006-05-24 03:30:31 +0000353 * Add a new parameter to a parameter list.
354 * \param paramList the list to add the parameter to
355 * \param name the parameter name, will be duplicated/copied!
356 * \param values initial parameter value, 4 GLfloats
357 * \param type type of parameter, such as
Brian Paul16241622005-11-03 02:26:47 +0000358 * \return index of new parameter in the list, or -1 if error (out of mem)
Michal Krol2861e732004-03-29 11:09:34 +0000359 */
360static GLint
Brian Paul122629f2006-07-20 16:49:57 +0000361add_parameter(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000362 const char *name, const GLfloat values[4],
Brian Paul613e1ad2005-11-05 02:15:21 +0000363 enum register_file type)
Michal Krol2861e732004-03-29 11:09:34 +0000364{
365 const GLuint n = paramList->NumParameters;
366
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000367 if (n == paramList->Size) {
Brian Paul65a51c02006-05-24 03:30:31 +0000368 /* Need to grow the parameter list array */
369 if (paramList->Size == 0)
Keith Whitwell9899f582005-06-08 21:57:45 +0000370 paramList->Size = 8;
Brian Paul65a51c02006-05-24 03:30:31 +0000371 else
372 paramList->Size *= 2;
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000373
Brian Paul65a51c02006-05-24 03:30:31 +0000374 /* realloc arrays */
Brian Paul122629f2006-07-20 16:49:57 +0000375 paramList->Parameters = (struct gl_program_parameter *)
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000376 _mesa_realloc(paramList->Parameters,
Brian Paul122629f2006-07-20 16:49:57 +0000377 n * sizeof(struct gl_program_parameter),
378 paramList->Size * sizeof(struct gl_program_parameter));
Keith Whitwell9899f582005-06-08 21:57:45 +0000379
Brian Paul65a51c02006-05-24 03:30:31 +0000380 paramList->ParameterValues = (GLfloat (*)[4])
381 _mesa_align_realloc(paramList->ParameterValues, /* old buf */
382 n * 4 * sizeof(GLfloat), /* old size */
383 paramList->Size * 4 *sizeof(GLfloat), /* new sz */
384 16);
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000385 }
Keith Whitwell7c26b612005-04-21 14:46:57 +0000386
387 if (!paramList->Parameters ||
388 !paramList->ParameterValues) {
Michal Krol2861e732004-03-29 11:09:34 +0000389 /* out of memory */
390 paramList->NumParameters = 0;
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000391 paramList->Size = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000392 return -1;
393 }
394 else {
395 paramList->NumParameters = n + 1;
Keith Whitwella42fe192005-05-10 18:22:19 +0000396
397 _mesa_memset(&paramList->Parameters[n], 0,
Brian Paul122629f2006-07-20 16:49:57 +0000398 sizeof(struct gl_program_parameter));
Keith Whitwella42fe192005-05-10 18:22:19 +0000399
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000400 paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
Michal Krol2861e732004-03-29 11:09:34 +0000401 paramList->Parameters[n].Type = type;
402 if (values)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000403 COPY_4V(paramList->ParameterValues[n], values);
Michal Krol2861e732004-03-29 11:09:34 +0000404 return (GLint) n;
405 }
406}
407
408
409/**
410 * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
411 * \return index of the new entry in the parameter list
412 */
413GLint
Brian Paul122629f2006-07-20 16:49:57 +0000414_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000415 const char *name, const GLfloat values[4])
416{
Brian Paul613e1ad2005-11-05 02:15:21 +0000417 return add_parameter(paramList, name, values, PROGRAM_NAMED_PARAM);
Michal Krol2861e732004-03-29 11:09:34 +0000418}
419
420
421/**
422 * Add a new unnamed constant to the parameter list.
423 * \param paramList - the parameter list
424 * \param values - four float values
425 * \return index of the new parameter.
426 */
427GLint
Brian Paul122629f2006-07-20 16:49:57 +0000428_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000429 const char *name, const GLfloat values[4])
430{
Brian Paul613e1ad2005-11-05 02:15:21 +0000431 return add_parameter(paramList, name, values, PROGRAM_CONSTANT);
Michal Krol2861e732004-03-29 11:09:34 +0000432}
433
434
435/**
436 * Add a new unnamed constant to the parameter list.
437 * \param paramList - the parameter list
438 * \param values - four float values
439 * \return index of the new parameter.
440 */
441GLint
Brian Paul122629f2006-07-20 16:49:57 +0000442_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000443 const GLfloat values[4])
444{
Brian Paul613e1ad2005-11-05 02:15:21 +0000445 return add_parameter(paramList, NULL, values, PROGRAM_CONSTANT);
Michal Krol2861e732004-03-29 11:09:34 +0000446}
447
448
449/**
450 * Add a new state reference to the parameter list.
451 * \param paramList - the parameter list
452 * \param state - an array of 6 state tokens
453 *
454 * \return index of the new parameter.
455 */
456GLint
Brian Paul122629f2006-07-20 16:49:57 +0000457_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
Brian Paul16241622005-11-03 02:26:47 +0000458 const GLint *stateTokens)
Michal Krol2861e732004-03-29 11:09:34 +0000459{
Brian Paul16241622005-11-03 02:26:47 +0000460 /* XXX we should probably search the current parameter list to see if
461 * the new state reference is already present.
Michal Krol2861e732004-03-29 11:09:34 +0000462 */
Brian Paul16241622005-11-03 02:26:47 +0000463 GLint index;
Brian Paul7b98b402005-11-12 23:25:49 +0000464 const char *name = make_state_string(stateTokens);
Michal Krol2861e732004-03-29 11:09:34 +0000465
Brian Paul7b98b402005-11-12 23:25:49 +0000466 index = add_parameter(paramList, name, NULL, PROGRAM_STATE_VAR);
Brian Paul16241622005-11-03 02:26:47 +0000467 if (index >= 0) {
468 GLuint i;
Brian Paul65a51c02006-05-24 03:30:31 +0000469 for (i = 0; i < 6; i++) {
Brian Paul16241622005-11-03 02:26:47 +0000470 paramList->Parameters[index].StateIndexes[i]
471 = (enum state_index) stateTokens[i];
Brian Paul65a51c02006-05-24 03:30:31 +0000472 }
473 paramList->StateFlags |=
Keith Whitwellec1ffd92005-11-22 12:12:17 +0000474 make_state_flags(stateTokens);
Brian Paul16241622005-11-03 02:26:47 +0000475 }
Michal Krol2861e732004-03-29 11:09:34 +0000476
Brian Paul5a67af92006-05-24 03:25:22 +0000477 /* free name string here since we duplicated it in add_parameter() */
478 _mesa_free((void *) name);
479
Brian Paul16241622005-11-03 02:26:47 +0000480 return index;
Michal Krol2861e732004-03-29 11:09:34 +0000481}
482
483
484/**
485 * Lookup a parameter value by name in the given parameter list.
486 * \return pointer to the float[4] values.
487 */
488GLfloat *
Brian Paul122629f2006-07-20 16:49:57 +0000489_mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000490 GLsizei nameLen, const char *name)
491{
492 GLuint i;
493
494 if (!paramList)
495 return NULL;
496
497 if (nameLen == -1) {
498 /* name is null-terminated */
499 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000500 if (paramList->Parameters[i].Name &&
501 _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000502 return paramList->ParameterValues[i];
Michal Krol2861e732004-03-29 11:09:34 +0000503 }
504 }
505 else {
506 /* name is not null-terminated, use nameLen */
507 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000508 if (paramList->Parameters[i].Name &&
509 _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
Michal Krol2861e732004-03-29 11:09:34 +0000510 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000511 return paramList->ParameterValues[i];
Michal Krol2861e732004-03-29 11:09:34 +0000512 }
513 }
514 return NULL;
515}
516
517
518/**
519 * Lookup a parameter index by name in the given parameter list.
520 * \return index of parameter in the list.
521 */
522GLint
Brian Paul122629f2006-07-20 16:49:57 +0000523_mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList,
Michal Krol2861e732004-03-29 11:09:34 +0000524 GLsizei nameLen, const char *name)
525{
526 GLint i;
527
528 if (!paramList)
529 return -1;
530
531 if (nameLen == -1) {
532 /* name is null-terminated */
533 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000534 if (paramList->Parameters[i].Name &&
535 _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
Michal Krol2861e732004-03-29 11:09:34 +0000536 return i;
537 }
538 }
539 else {
540 /* name is not null-terminated, use nameLen */
541 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000542 if (paramList->Parameters[i].Name &&
543 _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
Michal Krol2861e732004-03-29 11:09:34 +0000544 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
545 return i;
546 }
547 }
548 return -1;
549}
550
551
552/**
553 * Use the list of tokens in the state[] array to find global GL state
554 * and return it in <value>. Usually, four values are returned in <value>
555 * but matrix queries may return as many as 16 values.
556 * This function is used for ARB vertex/fragment programs.
557 * The program parser will produce the state[] values.
558 */
559static void
560_mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
561 GLfloat *value)
562{
563 switch (state[0]) {
564 case STATE_MATERIAL:
565 {
566 /* state[1] is either 0=front or 1=back side */
567 const GLuint face = (GLuint) state[1];
568 /* state[2] is the material attribute */
569 switch (state[2]) {
570 case STATE_AMBIENT:
571 if (face == 0)
572 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
573 else
574 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
575 return;
576 case STATE_DIFFUSE:
577 if (face == 0)
578 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
579 else
580 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
581 return;
582 case STATE_SPECULAR:
583 if (face == 0)
584 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
585 else
586 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
587 return;
588 case STATE_EMISSION:
589 if (face == 0)
590 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
591 else
592 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
593 return;
594 case STATE_SHININESS:
595 if (face == 0)
596 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
597 else
598 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
599 value[1] = 0.0F;
600 value[2] = 0.0F;
601 value[3] = 1.0F;
602 return;
603 default:
604 _mesa_problem(ctx, "Invalid material state in fetch_state");
605 return;
606 }
Alan Hourihane22ae6332004-12-02 13:29:40 +0000607 }
Michal Krol2861e732004-03-29 11:09:34 +0000608 case STATE_LIGHT:
609 {
610 /* state[1] is the light number */
611 const GLuint ln = (GLuint) state[1];
612 /* state[2] is the light attribute */
613 switch (state[2]) {
614 case STATE_AMBIENT:
615 COPY_4V(value, ctx->Light.Light[ln].Ambient);
616 return;
617 case STATE_DIFFUSE:
618 COPY_4V(value, ctx->Light.Light[ln].Diffuse);
619 return;
620 case STATE_SPECULAR:
621 COPY_4V(value, ctx->Light.Light[ln].Specular);
622 return;
623 case STATE_POSITION:
624 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
625 return;
626 case STATE_ATTENUATION:
627 value[0] = ctx->Light.Light[ln].ConstantAttenuation;
628 value[1] = ctx->Light.Light[ln].LinearAttenuation;
629 value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
630 value[3] = ctx->Light.Light[ln].SpotExponent;
631 return;
632 case STATE_SPOT_DIRECTION:
Brian Paul52bf0052005-04-20 23:47:03 +0000633 COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
634 value[3] = ctx->Light.Light[ln]._CosCutoff;
Michal Krol2861e732004-03-29 11:09:34 +0000635 return;
636 case STATE_HALF:
637 {
638 GLfloat eye_z[] = {0, 0, 1};
639
640 /* Compute infinite half angle vector:
641 * half-vector = light_position + (0, 0, 1)
642 * and then normalize. w = 0
Keith Whitwell7c26b612005-04-21 14:46:57 +0000643 *
644 * light.EyePosition.w should be 0 for infinite lights.
Michal Krol2861e732004-03-29 11:09:34 +0000645 */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000646 ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
647 NORMALIZE_3FV(value);
648 value[3] = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000649 }
650 return;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000651 case STATE_POSITION_NORMALIZED:
652 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
653 NORMALIZE_3FV( value );
654 return;
Michal Krol2861e732004-03-29 11:09:34 +0000655 default:
656 _mesa_problem(ctx, "Invalid light state in fetch_state");
657 return;
658 }
659 }
Michal Krol2861e732004-03-29 11:09:34 +0000660 case STATE_LIGHTMODEL_AMBIENT:
661 COPY_4V(value, ctx->Light.Model.Ambient);
662 return;
663 case STATE_LIGHTMODEL_SCENECOLOR:
664 if (state[1] == 0) {
665 /* front */
666 GLint i;
Keith Whitwell78803b22005-04-15 12:57:23 +0000667 for (i = 0; i < 3; i++) {
Michal Krol2861e732004-03-29 11:09:34 +0000668 value[i] = ctx->Light.Model.Ambient[i]
669 * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
670 + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
671 }
Keith Whitwell78803b22005-04-15 12:57:23 +0000672 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
Michal Krol2861e732004-03-29 11:09:34 +0000673 }
674 else {
675 /* back */
676 GLint i;
Keith Whitwell78803b22005-04-15 12:57:23 +0000677 for (i = 0; i < 3; i++) {
Michal Krol2861e732004-03-29 11:09:34 +0000678 value[i] = ctx->Light.Model.Ambient[i]
679 * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
680 + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
681 }
Keith Whitwell78803b22005-04-15 12:57:23 +0000682 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
Michal Krol2861e732004-03-29 11:09:34 +0000683 }
684 return;
685 case STATE_LIGHTPROD:
686 {
687 const GLuint ln = (GLuint) state[1];
688 const GLuint face = (GLuint) state[2];
689 GLint i;
690 ASSERT(face == 0 || face == 1);
691 switch (state[3]) {
692 case STATE_AMBIENT:
693 for (i = 0; i < 3; i++) {
694 value[i] = ctx->Light.Light[ln].Ambient[i] *
695 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
696 }
697 /* [3] = material alpha */
698 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
699 return;
700 case STATE_DIFFUSE:
701 for (i = 0; i < 3; i++) {
702 value[i] = ctx->Light.Light[ln].Diffuse[i] *
703 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
704 }
705 /* [3] = material alpha */
706 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
707 return;
708 case STATE_SPECULAR:
709 for (i = 0; i < 3; i++) {
710 value[i] = ctx->Light.Light[ln].Specular[i] *
711 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
712 }
713 /* [3] = material alpha */
714 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
715 return;
716 default:
717 _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
718 return;
719 }
720 }
Michal Krol2861e732004-03-29 11:09:34 +0000721 case STATE_TEXGEN:
722 {
723 /* state[1] is the texture unit */
724 const GLuint unit = (GLuint) state[1];
725 /* state[2] is the texgen attribute */
726 switch (state[2]) {
727 case STATE_TEXGEN_EYE_S:
728 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
729 return;
730 case STATE_TEXGEN_EYE_T:
731 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
732 return;
733 case STATE_TEXGEN_EYE_R:
734 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
735 return;
736 case STATE_TEXGEN_EYE_Q:
737 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
738 return;
739 case STATE_TEXGEN_OBJECT_S:
740 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
741 return;
742 case STATE_TEXGEN_OBJECT_T:
743 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
744 return;
745 case STATE_TEXGEN_OBJECT_R:
746 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
747 return;
748 case STATE_TEXGEN_OBJECT_Q:
749 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
750 return;
751 default:
752 _mesa_problem(ctx, "Invalid texgen state in fetch_state");
753 return;
754 }
755 }
Michal Krol2861e732004-03-29 11:09:34 +0000756 case STATE_TEXENV_COLOR:
757 {
758 /* state[1] is the texture unit */
759 const GLuint unit = (GLuint) state[1];
760 COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
761 }
762 return;
763 case STATE_FOG_COLOR:
764 COPY_4V(value, ctx->Fog.Color);
765 return;
766 case STATE_FOG_PARAMS:
767 value[0] = ctx->Fog.Density;
768 value[1] = ctx->Fog.Start;
769 value[2] = ctx->Fog.End;
770 value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
771 return;
772 case STATE_CLIPPLANE:
773 {
774 const GLuint plane = (GLuint) state[1];
775 COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
776 }
777 return;
778 case STATE_POINT_SIZE:
779 value[0] = ctx->Point.Size;
780 value[1] = ctx->Point.MinSize;
781 value[2] = ctx->Point.MaxSize;
782 value[3] = ctx->Point.Threshold;
783 return;
784 case STATE_POINT_ATTENUATION:
785 value[0] = ctx->Point.Params[0];
786 value[1] = ctx->Point.Params[1];
787 value[2] = ctx->Point.Params[2];
788 value[3] = 1.0F;
789 return;
790 case STATE_MATRIX:
791 {
792 /* state[1] = modelview, projection, texture, etc. */
793 /* state[2] = which texture matrix or program matrix */
794 /* state[3] = first column to fetch */
795 /* state[4] = last column to fetch */
796 /* state[5] = transpose, inverse or invtrans */
797
798 const GLmatrix *matrix;
799 const enum state_index mat = state[1];
800 const GLuint index = (GLuint) state[2];
801 const GLuint first = (GLuint) state[3];
802 const GLuint last = (GLuint) state[4];
803 const enum state_index modifier = state[5];
804 const GLfloat *m;
805 GLuint row, i;
806 if (mat == STATE_MODELVIEW) {
807 matrix = ctx->ModelviewMatrixStack.Top;
808 }
809 else if (mat == STATE_PROJECTION) {
810 matrix = ctx->ProjectionMatrixStack.Top;
811 }
812 else if (mat == STATE_MVP) {
813 matrix = &ctx->_ModelProjectMatrix;
814 }
815 else if (mat == STATE_TEXTURE) {
816 matrix = ctx->TextureMatrixStack[index].Top;
817 }
818 else if (mat == STATE_PROGRAM) {
819 matrix = ctx->ProgramMatrixStack[index].Top;
820 }
821 else {
822 _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
823 return;
824 }
825 if (modifier == STATE_MATRIX_INVERSE ||
826 modifier == STATE_MATRIX_INVTRANS) {
Keith Whitwell78803b22005-04-15 12:57:23 +0000827 /* Be sure inverse is up to date:
828 */
Brian Paul122629f2006-07-20 16:49:57 +0000829 _math_matrix_alloc_inv( (GLmatrix *) matrix );
Jouk Jansen49b1d952005-04-18 13:05:24 +0000830 _math_matrix_analyse( (GLmatrix*) matrix );
Michal Krol2861e732004-03-29 11:09:34 +0000831 m = matrix->inv;
832 }
833 else {
834 m = matrix->m;
835 }
836 if (modifier == STATE_MATRIX_TRANSPOSE ||
837 modifier == STATE_MATRIX_INVTRANS) {
838 for (i = 0, row = first; row <= last; row++) {
839 value[i++] = m[row * 4 + 0];
840 value[i++] = m[row * 4 + 1];
841 value[i++] = m[row * 4 + 2];
842 value[i++] = m[row * 4 + 3];
843 }
844 }
845 else {
846 for (i = 0, row = first; row <= last; row++) {
847 value[i++] = m[row + 0];
848 value[i++] = m[row + 4];
849 value[i++] = m[row + 8];
850 value[i++] = m[row + 12];
851 }
852 }
853 }
854 return;
855 case STATE_DEPTH_RANGE:
Brian Paul824fdf02004-06-29 00:00:06 +0000856 value[0] = ctx->Viewport.Near; /* near */
857 value[1] = ctx->Viewport.Far; /* far */
858 value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
859 value[3] = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000860 return;
861 case STATE_FRAGMENT_PROGRAM:
862 {
863 /* state[1] = {STATE_ENV, STATE_LOCAL} */
864 /* state[2] = parameter index */
Brian Paul824fdf02004-06-29 00:00:06 +0000865 const int idx = (int) state[2];
Michal Krol2861e732004-03-29 11:09:34 +0000866 switch (state[1]) {
867 case STATE_ENV:
Brian Paul824fdf02004-06-29 00:00:06 +0000868 COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
Michal Krol2861e732004-03-29 11:09:34 +0000869 break;
Michal Krol2861e732004-03-29 11:09:34 +0000870 case STATE_LOCAL:
871 COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
Brian Paul824fdf02004-06-29 00:00:06 +0000872 break;
Michal Krol2861e732004-03-29 11:09:34 +0000873 default:
874 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
875 return;
Brian Paul824fdf02004-06-29 00:00:06 +0000876 }
877 }
Michal Krol2861e732004-03-29 11:09:34 +0000878 return;
879
880 case STATE_VERTEX_PROGRAM:
Brian Paul824fdf02004-06-29 00:00:06 +0000881 {
Michal Krol2861e732004-03-29 11:09:34 +0000882 /* state[1] = {STATE_ENV, STATE_LOCAL} */
883 /* state[2] = parameter index */
Brian Paul824fdf02004-06-29 00:00:06 +0000884 const int idx = (int) state[2];
Michal Krol2861e732004-03-29 11:09:34 +0000885 switch (state[1]) {
886 case STATE_ENV:
Brian Paul824fdf02004-06-29 00:00:06 +0000887 COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
Michal Krol2861e732004-03-29 11:09:34 +0000888 break;
Michal Krol2861e732004-03-29 11:09:34 +0000889 case STATE_LOCAL:
890 COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
Brian Paul824fdf02004-06-29 00:00:06 +0000891 break;
Michal Krol2861e732004-03-29 11:09:34 +0000892 default:
893 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
894 return;
Brian Paul824fdf02004-06-29 00:00:06 +0000895 }
896 }
Michal Krol2861e732004-03-29 11:09:34 +0000897 return;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000898
899 case STATE_INTERNAL:
900 {
901 switch (state[1]) {
902 case STATE_NORMAL_SCALE:
903 ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
904 break;
905 default:
906 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
907 return;
908 }
909 }
910 return;
911
Michal Krol2861e732004-03-29 11:09:34 +0000912 default:
Brian Paul824fdf02004-06-29 00:00:06 +0000913 _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
Michal Krol2861e732004-03-29 11:09:34 +0000914 return;
915 }
916}
917
918
Brian Paul65a51c02006-05-24 03:30:31 +0000919/**
920 * Return a bit mask of the Mesa state flags under which a parameter's
Keith Whitwellec1ffd92005-11-22 12:12:17 +0000921 * value might change.
922 */
923static GLuint make_state_flags(const GLint state[])
924{
925 switch (state[0]) {
926 case STATE_MATERIAL:
927 case STATE_LIGHT:
928 case STATE_LIGHTMODEL_AMBIENT:
929 case STATE_LIGHTMODEL_SCENECOLOR:
930 case STATE_LIGHTPROD:
931 return _NEW_LIGHT;
932
933 case STATE_TEXGEN:
934 case STATE_TEXENV_COLOR:
935 return _NEW_TEXTURE;
936
937 case STATE_FOG_COLOR:
938 case STATE_FOG_PARAMS:
939 return _NEW_FOG;
940
941 case STATE_CLIPPLANE:
942 return _NEW_TRANSFORM;
943
944 case STATE_POINT_SIZE:
945 case STATE_POINT_ATTENUATION:
946 return _NEW_POINT;
947
948 case STATE_MATRIX:
949 switch (state[1]) {
950 case STATE_MODELVIEW:
951 return _NEW_MODELVIEW;
952 case STATE_PROJECTION:
953 return _NEW_PROJECTION;
954 case STATE_MVP:
955 return _NEW_MODELVIEW | _NEW_PROJECTION;
956 case STATE_TEXTURE:
957 return _NEW_TEXTURE_MATRIX;
958 case STATE_PROGRAM:
959 return _NEW_TRACK_MATRIX;
960 default:
Brian Paul65a51c02006-05-24 03:30:31 +0000961 _mesa_problem(NULL, "unexpected matrix in make_state_flags()");
Keith Whitwellec1ffd92005-11-22 12:12:17 +0000962 return 0;
963 }
964
965 case STATE_DEPTH_RANGE:
966 return _NEW_VIEWPORT;
967
968 case STATE_FRAGMENT_PROGRAM:
969 case STATE_VERTEX_PROGRAM:
970 return _NEW_PROGRAM;
971
972 case STATE_INTERNAL:
973 switch (state[1]) {
974 case STATE_NORMAL_SCALE:
975 return _NEW_MODELVIEW;
976 default:
Brian Paul65a51c02006-05-24 03:30:31 +0000977 _mesa_problem(NULL, "unexpected int. state in make_state_flags()");
Keith Whitwellec1ffd92005-11-22 12:12:17 +0000978 return 0;
979 }
980
981 default:
Brian Paul65a51c02006-05-24 03:30:31 +0000982 _mesa_problem(NULL, "unexpected state[0] in make_state_flags()");
Keith Whitwellec1ffd92005-11-22 12:12:17 +0000983 return 0;
984 }
985}
986
987
Brian Paul7b98b402005-11-12 23:25:49 +0000988static void
989append(char *dst, const char *src)
990{
991 while (*dst)
992 dst++;
993 while (*src)
994 *dst++ = *src++;
995 *dst = 0;
996}
997
Brian Paul65a51c02006-05-24 03:30:31 +0000998
Brian Paul7b98b402005-11-12 23:25:49 +0000999static void
1000append_token(char *dst, enum state_index k)
1001{
1002 switch (k) {
1003 case STATE_MATERIAL:
1004 append(dst, "material.");
1005 break;
1006 case STATE_LIGHT:
1007 append(dst, "light");
1008 break;
1009 case STATE_LIGHTMODEL_AMBIENT:
1010 append(dst, "lightmodel.ambient");
1011 break;
1012 case STATE_LIGHTMODEL_SCENECOLOR:
1013 break;
1014 case STATE_LIGHTPROD:
1015 append(dst, "lightprod");
1016 break;
1017 case STATE_TEXGEN:
1018 append(dst, "texgen");
1019 break;
1020 case STATE_FOG_COLOR:
1021 append(dst, "fog.color");
1022 break;
1023 case STATE_FOG_PARAMS:
1024 append(dst, "fog.params");
1025 break;
1026 case STATE_CLIPPLANE:
1027 append(dst, "clip");
1028 break;
1029 case STATE_POINT_SIZE:
1030 append(dst, "point.size");
1031 break;
1032 case STATE_POINT_ATTENUATION:
1033 append(dst, "point.attenuation");
1034 break;
1035 case STATE_MATRIX:
1036 append(dst, "matrix.");
1037 break;
1038 case STATE_MODELVIEW:
1039 append(dst, "modelview");
1040 break;
1041 case STATE_PROJECTION:
1042 append(dst, "projection");
1043 break;
1044 case STATE_MVP:
1045 append(dst, "mvp");
1046 break;
1047 case STATE_TEXTURE:
1048 append(dst, "texture");
1049 break;
1050 case STATE_PROGRAM:
1051 append(dst, "program");
1052 break;
1053 case STATE_MATRIX_INVERSE:
1054 append(dst, ".inverse");
1055 break;
1056 case STATE_MATRIX_TRANSPOSE:
1057 append(dst, ".transpose");
1058 break;
1059 case STATE_MATRIX_INVTRANS:
1060 append(dst, ".invtrans");
1061 break;
1062 case STATE_AMBIENT:
1063 append(dst, "ambient");
1064 break;
1065 case STATE_DIFFUSE:
1066 append(dst, "diffuse");
1067 break;
1068 case STATE_SPECULAR:
1069 append(dst, "specular");
1070 break;
1071 case STATE_EMISSION:
1072 append(dst, "emission");
1073 break;
1074 case STATE_SHININESS:
1075 append(dst, "shininess");
1076 break;
1077 case STATE_HALF:
1078 append(dst, "half");
1079 break;
1080 case STATE_POSITION:
1081 append(dst, ".position");
1082 break;
1083 case STATE_ATTENUATION:
1084 append(dst, ".attenuation");
1085 break;
1086 case STATE_SPOT_DIRECTION:
1087 append(dst, ".spot.direction");
1088 break;
1089 case STATE_TEXGEN_EYE_S:
1090 append(dst, "eye.s");
1091 break;
1092 case STATE_TEXGEN_EYE_T:
1093 append(dst, "eye.t");
1094 break;
1095 case STATE_TEXGEN_EYE_R:
1096 append(dst, "eye.r");
1097 break;
1098 case STATE_TEXGEN_EYE_Q:
1099 append(dst, "eye.q");
1100 break;
1101 case STATE_TEXGEN_OBJECT_S:
1102 append(dst, "object.s");
1103 break;
1104 case STATE_TEXGEN_OBJECT_T:
1105 append(dst, "object.t");
1106 break;
1107 case STATE_TEXGEN_OBJECT_R:
1108 append(dst, "object.r");
1109 break;
1110 case STATE_TEXGEN_OBJECT_Q:
1111 append(dst, "object.q");
1112 break;
1113 case STATE_TEXENV_COLOR:
1114 append(dst, "texenv");
1115 break;
1116 case STATE_DEPTH_RANGE:
1117 append(dst, "depth.range");
1118 break;
1119 case STATE_VERTEX_PROGRAM:
1120 case STATE_FRAGMENT_PROGRAM:
1121 break;
1122 case STATE_ENV:
1123 append(dst, "env");
1124 break;
1125 case STATE_LOCAL:
1126 append(dst, "local");
1127 break;
1128 case STATE_INTERNAL:
1129 case STATE_NORMAL_SCALE:
1130 case STATE_POSITION_NORMALIZED:
1131 append(dst, "(internal)");
1132 break;
1133 default:
1134 ;
1135 }
1136}
1137
1138static void
1139append_face(char *dst, GLint face)
1140{
1141 if (face == 0)
1142 append(dst, "front.");
1143 else
1144 append(dst, "back.");
1145}
1146
1147static void
1148append_index(char *dst, GLint index)
1149{
1150 char s[20];
1151 _mesa_sprintf(s, "[%d].", index);
1152 append(dst, s);
1153}
1154
1155/**
1156 * Make a string from the given state vector.
1157 * For example, return "state.matrix.texture[2].inverse".
Brian Paul65a51c02006-05-24 03:30:31 +00001158 * Use _mesa_free() to deallocate the string.
Brian Paul7b98b402005-11-12 23:25:49 +00001159 */
1160static const char *
1161make_state_string(const GLint state[6])
1162{
1163 char str[1000] = "";
1164 char tmp[30];
1165
1166 append(str, "state.");
Brian Paul95801792005-12-06 15:41:43 +00001167 append_token(str, (enum state_index) state[0]);
Brian Paul7b98b402005-11-12 23:25:49 +00001168
1169 switch (state[0]) {
1170 case STATE_MATERIAL:
1171 append_face(str, state[1]);
Brian Paul95801792005-12-06 15:41:43 +00001172 append_token(str, (enum state_index) state[2]);
Brian Paul7b98b402005-11-12 23:25:49 +00001173 break;
1174 case STATE_LIGHT:
1175 append(str, "light");
1176 append_index(str, state[1]); /* light number [i]. */
Brian Paul95801792005-12-06 15:41:43 +00001177 append_token(str, (enum state_index) state[2]); /* coefficients */
Brian Paul7b98b402005-11-12 23:25:49 +00001178 break;
1179 case STATE_LIGHTMODEL_AMBIENT:
1180 append(str, "lightmodel.ambient");
1181 break;
1182 case STATE_LIGHTMODEL_SCENECOLOR:
1183 if (state[1] == 0) {
1184 append(str, "lightmodel.front.scenecolor");
1185 }
1186 else {
1187 append(str, "lightmodel.back.scenecolor");
1188 }
1189 break;
1190 case STATE_LIGHTPROD:
1191 append_index(str, state[1]); /* light number [i]. */
1192 append_face(str, state[2]);
Brian Paul95801792005-12-06 15:41:43 +00001193 append_token(str, (enum state_index) state[3]);
Brian Paul7b98b402005-11-12 23:25:49 +00001194 break;
1195 case STATE_TEXGEN:
1196 append_index(str, state[1]); /* tex unit [i] */
Brian Paul95801792005-12-06 15:41:43 +00001197 append_token(str, (enum state_index) state[2]); /* plane coef */
Brian Paul7b98b402005-11-12 23:25:49 +00001198 break;
1199 case STATE_TEXENV_COLOR:
1200 append_index(str, state[1]); /* tex unit [i] */
1201 append(str, "color");
1202 break;
1203 case STATE_FOG_COLOR:
1204 case STATE_FOG_PARAMS:
1205 break;
1206 case STATE_CLIPPLANE:
1207 append_index(str, state[1]); /* plane [i] */
1208 append(str, "plane");
1209 break;
1210 case STATE_POINT_SIZE:
1211 case STATE_POINT_ATTENUATION:
1212 break;
1213 case STATE_MATRIX:
1214 {
1215 /* state[1] = modelview, projection, texture, etc. */
1216 /* state[2] = which texture matrix or program matrix */
1217 /* state[3] = first column to fetch */
1218 /* state[4] = last column to fetch */
1219 /* state[5] = transpose, inverse or invtrans */
Brian Paul95801792005-12-06 15:41:43 +00001220 const enum state_index mat = (enum state_index) state[1];
Brian Paul7b98b402005-11-12 23:25:49 +00001221 const GLuint index = (GLuint) state[2];
1222 const GLuint first = (GLuint) state[3];
1223 const GLuint last = (GLuint) state[4];
Brian Paul95801792005-12-06 15:41:43 +00001224 const enum state_index modifier = (enum state_index) state[5];
Brian Paul7b98b402005-11-12 23:25:49 +00001225 append_token(str, mat);
1226 if (index)
1227 append_index(str, index);
1228 if (modifier)
1229 append_token(str, modifier);
1230 if (first == last)
1231 _mesa_sprintf(tmp, ".row[%d]", first);
1232 else
1233 _mesa_sprintf(tmp, ".row[%d..%d]", first, last);
1234 append(str, tmp);
1235 }
1236 break;
1237 case STATE_DEPTH_RANGE:
1238 break;
1239 case STATE_FRAGMENT_PROGRAM:
1240 case STATE_VERTEX_PROGRAM:
1241 /* state[1] = {STATE_ENV, STATE_LOCAL} */
1242 /* state[2] = parameter index */
Brian Paul95801792005-12-06 15:41:43 +00001243 append_token(str, (enum state_index) state[1]);
Brian Paul7b98b402005-11-12 23:25:49 +00001244 append_index(str, state[2]);
1245 break;
1246 case STATE_INTERNAL:
1247 break;
1248 default:
1249 _mesa_problem(NULL, "Invalid state in maka_state_string");
1250 break;
1251 }
1252
1253 return _mesa_strdup(str);
1254}
1255
1256
Michal Krol2861e732004-03-29 11:09:34 +00001257/**
1258 * Loop over all the parameters in a parameter list. If the parameter
1259 * is a GL state reference, look up the current value of that state
1260 * variable and put it into the parameter's Value[4] array.
1261 * This would be called at glBegin time when using a fragment program.
1262 */
1263void
1264_mesa_load_state_parameters(GLcontext *ctx,
Brian Paul122629f2006-07-20 16:49:57 +00001265 struct gl_program_parameter_list *paramList)
Michal Krol2861e732004-03-29 11:09:34 +00001266{
1267 GLuint i;
1268
1269 if (!paramList)
1270 return;
1271
1272 for (i = 0; i < paramList->NumParameters; i++) {
Brian Paul613e1ad2005-11-05 02:15:21 +00001273 if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001274 _mesa_fetch_state(ctx,
1275 paramList->Parameters[i].StateIndexes,
1276 paramList->ParameterValues[i]);
Michal Krol2861e732004-03-29 11:09:34 +00001277 }
1278 }
1279}
1280
1281
Brian Paul1fcdaf12005-11-05 19:12:36 +00001282/**
Brian Paulec770b82005-11-20 17:57:22 +00001283 * Initialize program instruction fields to defaults.
1284 */
1285void
1286_mesa_init_instruction(struct prog_instruction *inst)
1287{
1288 _mesa_bzero(inst, sizeof(struct prog_instruction));
1289
1290 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1291 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1292 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1293 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1294 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1295 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
1296
1297 inst->DstReg.File = PROGRAM_UNDEFINED;
1298 inst->DstReg.WriteMask = WRITEMASK_XYZW;
1299 inst->DstReg.CondMask = COND_TR;
1300 inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
1301
1302 inst->SaturateMode = SATURATE_OFF;
1303 inst->Precision = FLOAT32;
1304}
1305
1306
1307/**
Brian Paul1fcdaf12005-11-05 19:12:36 +00001308 * Basic info about each instruction
1309 */
1310struct instruction_info
1311{
1312 enum prog_opcode Opcode;
1313 const char *Name;
1314 GLuint NumSrcRegs;
1315};
1316
1317/**
1318 * Instruction info
1319 * \note Opcode should equal array index!
1320 */
1321static const struct instruction_info InstInfo[MAX_OPCODE] = {
1322 { OPCODE_ABS, "ABS", 1 },
1323 { OPCODE_ADD, "ADD", 2 },
Ian Romanick4884db62005-11-08 22:40:26 +00001324 { OPCODE_ARA, "ARA", 1 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001325 { OPCODE_ARL, "ARL", 1 },
Ian Romanick4884db62005-11-08 22:40:26 +00001326 { OPCODE_ARL_NV, "ARL", 1 },
1327 { OPCODE_ARR, "ARL", 1 },
1328 { OPCODE_BRA, "BRA", 1 },
1329 { OPCODE_CAL, "CAL", 1 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001330 { OPCODE_CMP, "CMP", 3 },
1331 { OPCODE_COS, "COS", 1 },
1332 { OPCODE_DDX, "DDX", 1 },
1333 { OPCODE_DDY, "DDY", 1 },
1334 { OPCODE_DP3, "DP3", 2 },
1335 { OPCODE_DP4, "DP4", 2 },
1336 { OPCODE_DPH, "DPH", 2 },
1337 { OPCODE_DST, "DST", 2 },
1338 { OPCODE_END, "END", 0 },
1339 { OPCODE_EX2, "EX2", 1 },
1340 { OPCODE_EXP, "EXP", 1 },
1341 { OPCODE_FLR, "FLR", 1 },
1342 { OPCODE_FRC, "FRC", 1 },
1343 { OPCODE_KIL, "KIL", 1 },
1344 { OPCODE_KIL_NV, "KIL", 0 },
1345 { OPCODE_LG2, "LG2", 1 },
1346 { OPCODE_LIT, "LIT", 1 },
1347 { OPCODE_LOG, "LOG", 1 },
1348 { OPCODE_LRP, "LRP", 3 },
1349 { OPCODE_MAD, "MAD", 3 },
1350 { OPCODE_MAX, "MAX", 2 },
1351 { OPCODE_MIN, "MIN", 2 },
1352 { OPCODE_MOV, "MOV", 1 },
1353 { OPCODE_MUL, "MUL", 2 },
1354 { OPCODE_PK2H, "PK2H", 1 },
1355 { OPCODE_PK2US, "PK2US", 1 },
1356 { OPCODE_PK4B, "PK4B", 1 },
1357 { OPCODE_PK4UB, "PK4UB", 1 },
1358 { OPCODE_POW, "POW", 2 },
Ian Romanick4884db62005-11-08 22:40:26 +00001359 { OPCODE_POPA, "POPA", 0 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001360 { OPCODE_PRINT, "PRINT", 1 },
Ian Romanick4884db62005-11-08 22:40:26 +00001361 { OPCODE_PUSHA, "PUSHA", 0 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001362 { OPCODE_RCC, "RCC", 1 },
1363 { OPCODE_RCP, "RCP", 1 },
Ian Romanick4884db62005-11-08 22:40:26 +00001364 { OPCODE_RET, "RET", 1 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001365 { OPCODE_RFL, "RFL", 1 },
1366 { OPCODE_RSQ, "RSQ", 1 },
1367 { OPCODE_SCS, "SCS", 1 },
1368 { OPCODE_SEQ, "SEQ", 2 },
1369 { OPCODE_SFL, "SFL", 0 },
1370 { OPCODE_SGE, "SGE", 2 },
1371 { OPCODE_SGT, "SGT", 2 },
1372 { OPCODE_SIN, "SIN", 1 },
1373 { OPCODE_SLE, "SLE", 2 },
1374 { OPCODE_SLT, "SLT", 2 },
1375 { OPCODE_SNE, "SNE", 2 },
Ian Romanick4884db62005-11-08 22:40:26 +00001376 { OPCODE_SSG, "SSG", 1 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001377 { OPCODE_STR, "STR", 0 },
1378 { OPCODE_SUB, "SUB", 2 },
1379 { OPCODE_SWZ, "SWZ", 1 },
1380 { OPCODE_TEX, "TEX", 1 },
1381 { OPCODE_TXB, "TXB", 1 },
1382 { OPCODE_TXD, "TXD", 3 },
Ian Romanick4884db62005-11-08 22:40:26 +00001383 { OPCODE_TXL, "TXL", 1 },
Brian Paul1fcdaf12005-11-05 19:12:36 +00001384 { OPCODE_TXP, "TXP", 1 },
1385 { OPCODE_TXP_NV, "TXP", 1 },
1386 { OPCODE_UP2H, "UP2H", 1 },
1387 { OPCODE_UP2US, "UP2US", 1 },
1388 { OPCODE_UP4B, "UP4B", 1 },
1389 { OPCODE_UP4UB, "UP4UB", 1 },
1390 { OPCODE_X2D, "X2D", 3 },
1391 { OPCODE_XPD, "XPD", 2 }
1392};
1393
1394
1395/**
1396 * Return the number of src registers for the given instruction/opcode.
1397 */
1398GLuint
1399_mesa_num_inst_src_regs(enum prog_opcode opcode)
1400{
1401 GLuint i;
1402#ifdef DEBUG
1403 for (i = 0; i < MAX_OPCODE; i++) {
1404 ASSERT(i == InstInfo[i].Opcode);
1405 }
1406#endif
1407 for (i = 0; i < MAX_OPCODE; i++) {
1408 if (InstInfo[i].Opcode == opcode) {
1409 return InstInfo[i].NumSrcRegs;
1410 }
1411 }
1412 _mesa_problem(NULL, "invalid opcode in _mesa_num_inst_src_regs");
1413 return 0;
1414}
1415
1416
1417/**
1418 * Return string name for given program opcode.
1419 */
1420const char *
1421_mesa_opcode_string(enum prog_opcode opcode)
1422{
1423 ASSERT(opcode < MAX_OPCODE);
1424 return InstInfo[opcode].Name;
1425}
1426
Brian Paulbf41bc02005-11-05 19:32:36 +00001427/**
1428 * Return string name for given program/register file.
1429 */
Brian Paul30d6a4b2005-11-05 20:18:18 +00001430static const char *
1431program_file_string(enum register_file f)
Brian Paulbf41bc02005-11-05 19:32:36 +00001432{
1433 switch (f) {
1434 case PROGRAM_TEMPORARY:
1435 return "TEMP";
1436 case PROGRAM_LOCAL_PARAM:
1437 return "LOCAL";
1438 case PROGRAM_ENV_PARAM:
1439 return "ENV";
1440 case PROGRAM_STATE_VAR:
1441 return "STATE";
1442 case PROGRAM_INPUT:
1443 return "INPUT";
1444 case PROGRAM_OUTPUT:
1445 return "OUTPUT";
1446 case PROGRAM_NAMED_PARAM:
1447 return "NAMED";
1448 case PROGRAM_CONSTANT:
1449 return "CONST";
1450 case PROGRAM_WRITE_ONLY:
1451 return "WRITE_ONLY";
1452 case PROGRAM_ADDRESS:
1453 return "ADDR";
1454 default:
1455 return "!unkown!";
1456 }
1457}
1458
Michal Krol2861e732004-03-29 11:09:34 +00001459
Brian Paul30d6a4b2005-11-05 20:18:18 +00001460/**
1461 * Return a string representation of the given swizzle word.
Brian Paul7b98b402005-11-12 23:25:49 +00001462 * If extended is true, use extended (comma-separated) format.
Brian Paul30d6a4b2005-11-05 20:18:18 +00001463 */
1464static const char *
Brian Paul7b98b402005-11-12 23:25:49 +00001465swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended)
Brian Paul30d6a4b2005-11-05 20:18:18 +00001466{
1467 static const char swz[] = "xyzw01";
1468 static char s[20];
1469 GLuint i = 0;
1470
Brian Paul7b98b402005-11-12 23:25:49 +00001471 if (!extended && swizzle == SWIZZLE_NOOP && negateBase == 0)
Brian Paul30d6a4b2005-11-05 20:18:18 +00001472 return ""; /* no swizzle/negation */
1473
Brian Paul7b98b402005-11-12 23:25:49 +00001474 if (!extended)
1475 s[i++] = '.';
Brian Paul30d6a4b2005-11-05 20:18:18 +00001476
1477 if (negateBase & 0x1)
1478 s[i++] = '-';
1479 s[i++] = swz[GET_SWZ(swizzle, 0)];
1480
Brian Paul7b98b402005-11-12 23:25:49 +00001481 if (extended) {
1482 s[i++] = ',';
1483 }
1484
Brian Paul30d6a4b2005-11-05 20:18:18 +00001485 if (negateBase & 0x2)
1486 s[i++] = '-';
1487 s[i++] = swz[GET_SWZ(swizzle, 1)];
1488
Brian Paul7b98b402005-11-12 23:25:49 +00001489 if (extended) {
1490 s[i++] = ',';
1491 }
1492
Brian Paul30d6a4b2005-11-05 20:18:18 +00001493 if (negateBase & 0x4)
1494 s[i++] = '-';
1495 s[i++] = swz[GET_SWZ(swizzle, 2)];
1496
Brian Paul7b98b402005-11-12 23:25:49 +00001497 if (extended) {
1498 s[i++] = ',';
1499 }
1500
Brian Paul30d6a4b2005-11-05 20:18:18 +00001501 if (negateBase & 0x8)
1502 s[i++] = '-';
1503 s[i++] = swz[GET_SWZ(swizzle, 3)];
1504
1505 s[i] = 0;
1506 return s;
1507}
1508
1509
1510static const char *
1511writemask_string(GLuint writeMask)
1512{
1513 static char s[10];
1514 GLuint i = 0;
1515
1516 if (writeMask == WRITEMASK_XYZW)
1517 return "";
1518
1519 s[i++] = '.';
1520 if (writeMask & WRITEMASK_X)
1521 s[i++] = 'x';
1522 if (writeMask & WRITEMASK_Y)
1523 s[i++] = 'y';
1524 if (writeMask & WRITEMASK_Z)
1525 s[i++] = 'z';
1526 if (writeMask & WRITEMASK_W)
1527 s[i++] = 'w';
1528
1529 s[i] = 0;
1530 return s;
1531}
1532
Brian Paul7b98b402005-11-12 23:25:49 +00001533static void
1534print_dst_reg(const struct prog_dst_register *dstReg)
1535{
1536 _mesa_printf(" %s[%d]%s",
Brian Paul95801792005-12-06 15:41:43 +00001537 program_file_string((enum register_file) dstReg->File),
Brian Paul7b98b402005-11-12 23:25:49 +00001538 dstReg->Index,
1539 writemask_string(dstReg->WriteMask));
1540}
1541
1542static void
1543print_src_reg(const struct prog_src_register *srcReg)
1544{
1545 _mesa_printf("%s[%d]%s",
Brian Paul95801792005-12-06 15:41:43 +00001546 program_file_string((enum register_file) srcReg->File),
Brian Paul7b98b402005-11-12 23:25:49 +00001547 srcReg->Index,
1548 swizzle_string(srcReg->Swizzle,
1549 srcReg->NegateBase, GL_FALSE));
1550}
1551
Brian Paul30d6a4b2005-11-05 20:18:18 +00001552
1553/**
Brian Paulde997602005-11-12 17:53:14 +00001554 * Print a single vertex/fragment program instruction.
Brian Paul30d6a4b2005-11-05 20:18:18 +00001555 */
1556void
Brian Paulde997602005-11-12 17:53:14 +00001557_mesa_print_instruction(const struct prog_instruction *inst)
Brian Paul30d6a4b2005-11-05 20:18:18 +00001558{
Brian Paulde997602005-11-12 17:53:14 +00001559 switch (inst->Opcode) {
1560 case OPCODE_PRINT:
1561 _mesa_printf("PRINT '%s'", inst->Data);
1562 if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
1563 _mesa_printf(", ");
1564 _mesa_printf("%s[%d]%s",
Brian Paul95801792005-12-06 15:41:43 +00001565 program_file_string((enum register_file) inst->SrcReg[0].File),
Brian Paulde997602005-11-12 17:53:14 +00001566 inst->SrcReg[0].Index,
1567 swizzle_string(inst->SrcReg[0].Swizzle,
Brian Paul7b98b402005-11-12 23:25:49 +00001568 inst->SrcReg[0].NegateBase, GL_FALSE));
Brian Paulde997602005-11-12 17:53:14 +00001569 }
1570 _mesa_printf(";\n");
1571 break;
Brian Paul7b98b402005-11-12 23:25:49 +00001572 case OPCODE_SWZ:
1573 _mesa_printf("SWZ");
Brian Paule31ac052005-11-20 17:52:40 +00001574 if (inst->SaturateMode == SATURATE_ZERO_ONE)
Brian Paul7b98b402005-11-12 23:25:49 +00001575 _mesa_printf("_SAT");
1576 print_dst_reg(&inst->DstReg);
1577 _mesa_printf("%s[%d], %s;\n",
Brian Paul95801792005-12-06 15:41:43 +00001578 program_file_string((enum register_file) inst->SrcReg[0].File),
Brian Paul7b98b402005-11-12 23:25:49 +00001579 inst->SrcReg[0].Index,
1580 swizzle_string(inst->SrcReg[0].Swizzle,
1581 inst->SrcReg[0].NegateBase, GL_TRUE));
1582 break;
1583 case OPCODE_TEX:
1584 case OPCODE_TXP:
1585 case OPCODE_TXB:
1586 _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
Brian Paule31ac052005-11-20 17:52:40 +00001587 if (inst->SaturateMode == SATURATE_ZERO_ONE)
Brian Paul7b98b402005-11-12 23:25:49 +00001588 _mesa_printf("_SAT");
1589 _mesa_printf(" ");
1590 print_dst_reg(&inst->DstReg);
1591 _mesa_printf(", ");
1592 print_src_reg(&inst->SrcReg[0]);
1593 _mesa_printf(", texture[%d], ", inst->TexSrcUnit);
1594 switch (inst->TexSrcTarget) {
1595 case TEXTURE_1D_INDEX: _mesa_printf("1D"); break;
1596 case TEXTURE_2D_INDEX: _mesa_printf("2D"); break;
1597 case TEXTURE_3D_INDEX: _mesa_printf("3D"); break;
1598 case TEXTURE_CUBE_INDEX: _mesa_printf("CUBE"); break;
1599 case TEXTURE_RECT_INDEX: _mesa_printf("RECT"); break;
1600 default:
1601 ;
1602 }
1603 _mesa_printf("\n");
1604 break;
1605 case OPCODE_ARL:
1606 _mesa_printf("ARL addr.x, ");
1607 print_src_reg(&inst->SrcReg[0]);
1608 _mesa_printf(";\n");
1609 break;
1610 /* XXX may need for other special-case instructions */
Brian Paulde997602005-11-12 17:53:14 +00001611 default:
1612 /* typical alu instruction */
1613 {
1614 const GLuint numRegs = _mesa_num_inst_src_regs(inst->Opcode);
1615 GLuint j;
Brian Paul30d6a4b2005-11-05 20:18:18 +00001616
Brian Paulde997602005-11-12 17:53:14 +00001617 _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
Brian Paul30d6a4b2005-11-05 20:18:18 +00001618
Brian Paulde997602005-11-12 17:53:14 +00001619 /* frag prog only */
Brian Paule31ac052005-11-20 17:52:40 +00001620 if (inst->SaturateMode == SATURATE_ZERO_ONE)
Brian Paulde997602005-11-12 17:53:14 +00001621 _mesa_printf("_SAT");
1622
1623 if (inst->DstReg.File != PROGRAM_UNDEFINED) {
1624 _mesa_printf(" %s[%d]%s",
Brian Paul95801792005-12-06 15:41:43 +00001625 program_file_string((enum register_file) inst->DstReg.File),
Brian Paulde997602005-11-12 17:53:14 +00001626 inst->DstReg.Index,
1627 writemask_string(inst->DstReg.WriteMask));
1628 }
1629
1630 if (numRegs > 0)
Brian Paul02df9e12005-11-08 14:42:52 +00001631 _mesa_printf(", ");
Brian Paulde997602005-11-12 17:53:14 +00001632
1633 for (j = 0; j < numRegs; j++) {
Brian Paul7b98b402005-11-12 23:25:49 +00001634 print_src_reg(inst->SrcReg + j);
Brian Paulde997602005-11-12 17:53:14 +00001635 if (j + 1 < numRegs)
Brian Paul30d6a4b2005-11-05 20:18:18 +00001636 _mesa_printf(", ");
Brian Paul30d6a4b2005-11-05 20:18:18 +00001637 }
Brian Paulde997602005-11-12 17:53:14 +00001638
1639 _mesa_printf(";\n");
Brian Paul30d6a4b2005-11-05 20:18:18 +00001640 }
1641 }
1642}
1643
1644
Brian Paulde997602005-11-12 17:53:14 +00001645/**
1646 * Print a vertx/fragment program to stdout.
1647 * XXX this function could be greatly improved.
1648 */
1649void
Brian Paul122629f2006-07-20 16:49:57 +00001650_mesa_print_program(const struct gl_program *prog)
Brian Paulde997602005-11-12 17:53:14 +00001651{
1652 GLuint i;
1653 for (i = 0; i < prog->NumInstructions; i++) {
1654 _mesa_printf("%3d: ", i);
1655 _mesa_print_instruction(prog->Instructions + i);
1656 }
1657}
1658
1659
1660/**
1661 * Print all of a program's parameters.
1662 */
1663void
Brian Paul122629f2006-07-20 16:49:57 +00001664_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
Brian Paulde997602005-11-12 17:53:14 +00001665{
1666 GLint i;
1667
1668 _mesa_printf("NumInstructions=%d\n", prog->NumInstructions);
1669 _mesa_printf("NumTemporaries=%d\n", prog->NumTemporaries);
1670 _mesa_printf("NumParameters=%d\n", prog->NumParameters);
1671 _mesa_printf("NumAttributes=%d\n", prog->NumAttributes);
1672 _mesa_printf("NumAddressRegs=%d\n", prog->NumAddressRegs);
1673
1674 _mesa_load_state_parameters(ctx, prog->Parameters);
1675
1676#if 0
1677 _mesa_printf("Local Params:\n");
1678 for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){
1679 const GLfloat *p = prog->LocalParams[i];
1680 _mesa_printf("%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]);
1681 }
1682#endif
1683
1684 for (i = 0; i < prog->Parameters->NumParameters; i++){
Brian Paul122629f2006-07-20 16:49:57 +00001685 struct gl_program_parameter *param = prog->Parameters->Parameters + i;
Brian Paul7b98b402005-11-12 23:25:49 +00001686 const GLfloat *v = prog->Parameters->ParameterValues[i];
1687 _mesa_printf("param[%d] %s = {%.3f, %.3f, %.3f, %.3f};\n",
1688 i, param->Name, v[0], v[1], v[2], v[3]);
Brian Paulde997602005-11-12 17:53:14 +00001689 }
1690}
1691
Brian Paul30d6a4b2005-11-05 20:18:18 +00001692
1693
Michal Krol2861e732004-03-29 11:09:34 +00001694/**********************************************************************/
1695/* API functions */
1696/**********************************************************************/
1697
1698
1699/**
1700 * Bind a program (make it current)
1701 * \note Called from the GL API dispatcher by both glBindProgramNV
1702 * and glBindProgramARB.
1703 */
1704void GLAPIENTRY
1705_mesa_BindProgram(GLenum target, GLuint id)
1706{
Brian Paul122629f2006-07-20 16:49:57 +00001707 struct gl_program *prog;
Michal Krol2861e732004-03-29 11:09:34 +00001708 GET_CURRENT_CONTEXT(ctx);
1709 ASSERT_OUTSIDE_BEGIN_END(ctx);
1710
1711 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1712
Roland Scheideggere1e03b32006-03-03 15:03:04 +00001713 if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
1714 (ctx->Extensions.NV_vertex_program ||
1715 ctx->Extensions.ARB_vertex_program)) {
Brian Paul765f1a12004-09-14 22:28:27 +00001716 /*** Vertex program binding ***/
Brian Paul122629f2006-07-20 16:49:57 +00001717 struct gl_vertex_program *curProg = ctx->VertexProgram.Current;
Brian Paul765f1a12004-09-14 22:28:27 +00001718 if (curProg->Base.Id == id) {
1719 /* binding same program - no change */
Michal Krol2861e732004-03-29 11:09:34 +00001720 return;
Brian Paul765f1a12004-09-14 22:28:27 +00001721 }
1722 if (curProg->Base.Id != 0) {
1723 /* decrement refcount on previously bound vertex program */
1724 curProg->Base.RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +00001725 /* and delete if refcount goes below one */
Brian Paul765f1a12004-09-14 22:28:27 +00001726 if (curProg->Base.RefCount <= 0) {
Brian Paulea2943e2005-01-20 04:02:02 +00001727 /* the program ID was already removed from the hash table */
Brian Paul765f1a12004-09-14 22:28:27 +00001728 ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
Michal Krol2861e732004-03-29 11:09:34 +00001729 }
1730 }
1731 }
1732 else if ((target == GL_FRAGMENT_PROGRAM_NV
1733 && ctx->Extensions.NV_fragment_program) ||
1734 (target == GL_FRAGMENT_PROGRAM_ARB
1735 && ctx->Extensions.ARB_fragment_program)) {
Brian Paul765f1a12004-09-14 22:28:27 +00001736 /*** Fragment program binding ***/
Brian Paul122629f2006-07-20 16:49:57 +00001737 struct gl_fragment_program *curProg = ctx->FragmentProgram.Current;
Brian Paul765f1a12004-09-14 22:28:27 +00001738 if (curProg->Base.Id == id) {
1739 /* binding same program - no change */
Michal Krol2861e732004-03-29 11:09:34 +00001740 return;
Brian Paul765f1a12004-09-14 22:28:27 +00001741 }
1742 if (curProg->Base.Id != 0) {
1743 /* decrement refcount on previously bound fragment program */
1744 curProg->Base.RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +00001745 /* and delete if refcount goes below one */
Brian Paul765f1a12004-09-14 22:28:27 +00001746 if (curProg->Base.RefCount <= 0) {
Brian Paulea2943e2005-01-20 04:02:02 +00001747 /* the program ID was already removed from the hash table */
Brian Paul765f1a12004-09-14 22:28:27 +00001748 ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
Michal Krol2861e732004-03-29 11:09:34 +00001749 }
1750 }
1751 }
1752 else {
1753 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
1754 return;
1755 }
1756
1757 /* NOTE: binding to a non-existant program is not an error.
1758 * That's supposed to be caught in glBegin.
1759 */
1760 if (id == 0) {
Brian Paul765f1a12004-09-14 22:28:27 +00001761 /* Bind default program */
Michal Krol2861e732004-03-29 11:09:34 +00001762 prog = NULL;
Roland Scheideggere1e03b32006-03-03 15:03:04 +00001763 if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
Michal Krol2861e732004-03-29 11:09:34 +00001764 prog = ctx->Shared->DefaultVertexProgram;
1765 else
1766 prog = ctx->Shared->DefaultFragmentProgram;
1767 }
1768 else {
Brian Paul765f1a12004-09-14 22:28:27 +00001769 /* Bind user program */
Brian Paul4d12a052006-08-23 23:10:14 +00001770 prog = _mesa_lookup_program(ctx, id);
Brian Paul9ca83922004-10-02 15:16:59 +00001771 if (!prog || prog == &_mesa_DummyProgram) {
Michal Krol2861e732004-03-29 11:09:34 +00001772 /* allocate a new program now */
1773 prog = ctx->Driver.NewProgram(ctx, target, id);
1774 if (!prog) {
1775 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
1776 return;
1777 }
Michal Krol2861e732004-03-29 11:09:34 +00001778 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
1779 }
Brian Paul765f1a12004-09-14 22:28:27 +00001780 else if (prog->Target != target) {
1781 _mesa_error(ctx, GL_INVALID_OPERATION,
1782 "glBindProgramNV/ARB(target mismatch)");
1783 return;
1784 }
Michal Krol2861e732004-03-29 11:09:34 +00001785 }
1786
1787 /* bind now */
Roland Scheideggere1e03b32006-03-03 15:03:04 +00001788 if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
Brian Paul122629f2006-07-20 16:49:57 +00001789 ctx->VertexProgram.Current = (struct gl_vertex_program *) prog;
Michal Krol2861e732004-03-29 11:09:34 +00001790 }
1791 else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
Brian Paul122629f2006-07-20 16:49:57 +00001792 ctx->FragmentProgram.Current = (struct gl_fragment_program *) prog;
Michal Krol2861e732004-03-29 11:09:34 +00001793 }
1794
Brian Paul765f1a12004-09-14 22:28:27 +00001795 /* Never null pointers */
1796 ASSERT(ctx->VertexProgram.Current);
1797 ASSERT(ctx->FragmentProgram.Current);
1798
Michal Krol2861e732004-03-29 11:09:34 +00001799 if (prog)
1800 prog->RefCount++;
1801
1802 if (ctx->Driver.BindProgram)
1803 ctx->Driver.BindProgram(ctx, target, prog);
1804}
1805
1806
1807/**
1808 * Delete a list of programs.
1809 * \note Not compiled into display lists.
1810 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
1811 */
1812void GLAPIENTRY
1813_mesa_DeletePrograms(GLsizei n, const GLuint *ids)
1814{
1815 GLint i;
1816 GET_CURRENT_CONTEXT(ctx);
1817 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1818
1819 if (n < 0) {
1820 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
1821 return;
1822 }
1823
1824 for (i = 0; i < n; i++) {
1825 if (ids[i] != 0) {
Brian Paul4d12a052006-08-23 23:10:14 +00001826 struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
Brian Paul9ca83922004-10-02 15:16:59 +00001827 if (prog == &_mesa_DummyProgram) {
Brian Paul765f1a12004-09-14 22:28:27 +00001828 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1829 }
1830 else if (prog) {
1831 /* Unbind program if necessary */
Roland Scheideggere1e03b32006-03-03 15:03:04 +00001832 if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */
Michal Krol2861e732004-03-29 11:09:34 +00001833 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
1834 if (ctx->VertexProgram.Current &&
1835 ctx->VertexProgram.Current->Base.Id == ids[i]) {
1836 /* unbind this currently bound program */
1837 _mesa_BindProgram(prog->Target, 0);
1838 }
1839 }
1840 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
1841 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
1842 if (ctx->FragmentProgram.Current &&
1843 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
1844 /* unbind this currently bound program */
1845 _mesa_BindProgram(prog->Target, 0);
1846 }
1847 }
1848 else {
1849 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
1850 return;
1851 }
Brian Paulea2943e2005-01-20 04:02:02 +00001852 /* The ID is immediately available for re-use now */
1853 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1854 prog->RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +00001855 if (prog->RefCount <= 0) {
1856 ctx->Driver.DeleteProgram(ctx, prog);
1857 }
1858 }
Michal Krol2861e732004-03-29 11:09:34 +00001859 }
1860 }
1861}
1862
1863
1864/**
1865 * Generate a list of new program identifiers.
1866 * \note Not compiled into display lists.
1867 * \note Called by both glGenProgramsNV and glGenProgramsARB.
1868 */
1869void GLAPIENTRY
1870_mesa_GenPrograms(GLsizei n, GLuint *ids)
1871{
1872 GLuint first;
1873 GLuint i;
1874 GET_CURRENT_CONTEXT(ctx);
1875 ASSERT_OUTSIDE_BEGIN_END(ctx);
1876
1877 if (n < 0) {
1878 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
1879 return;
1880 }
1881
1882 if (!ids)
1883 return;
1884
1885 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
1886
Brian Paul765f1a12004-09-14 22:28:27 +00001887 /* Insert pointer to dummy program as placeholder */
Michal Krol2861e732004-03-29 11:09:34 +00001888 for (i = 0; i < (GLuint) n; i++) {
Brian Paul9ca83922004-10-02 15:16:59 +00001889 _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
Michal Krol2861e732004-03-29 11:09:34 +00001890 }
1891
1892 /* Return the program names */
1893 for (i = 0; i < (GLuint) n; i++) {
1894 ids[i] = first + i;
1895 }
1896}
1897
1898
1899/**
Brian Paul765f1a12004-09-14 22:28:27 +00001900 * Determine if id names a vertex or fragment program.
Michal Krol2861e732004-03-29 11:09:34 +00001901 * \note Not compiled into display lists.
1902 * \note Called from both glIsProgramNV and glIsProgramARB.
1903 * \param id is the program identifier
1904 * \return GL_TRUE if id is a program, else GL_FALSE.
1905 */
1906GLboolean GLAPIENTRY
1907_mesa_IsProgram(GLuint id)
1908{
1909 GET_CURRENT_CONTEXT(ctx);
1910 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1911
1912 if (id == 0)
1913 return GL_FALSE;
1914
Brian Paul4d12a052006-08-23 23:10:14 +00001915 if (_mesa_lookup_program(ctx, id))
Michal Krol2861e732004-03-29 11:09:34 +00001916 return GL_TRUE;
1917 else
1918 return GL_FALSE;
1919}
1920
1921
1922
1923/**********************************************************************/
1924/* GL_MESA_program_debug extension */
1925/**********************************************************************/
1926
1927
1928/* XXX temporary */
Daniel Borca0a13ceb2005-02-14 08:01:59 +00001929GLAPI void GLAPIENTRY
Michal Krol2861e732004-03-29 11:09:34 +00001930glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1931 GLvoid *data)
1932{
1933 _mesa_ProgramCallbackMESA(target, callback, data);
1934}
1935
1936
1937void
1938_mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1939 GLvoid *data)
1940{
1941 GET_CURRENT_CONTEXT(ctx);
1942
1943 switch (target) {
1944 case GL_FRAGMENT_PROGRAM_ARB:
1945 if (!ctx->Extensions.ARB_fragment_program) {
1946 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1947 return;
1948 }
1949 ctx->FragmentProgram.Callback = callback;
1950 ctx->FragmentProgram.CallbackData = data;
1951 break;
1952 case GL_FRAGMENT_PROGRAM_NV:
1953 if (!ctx->Extensions.NV_fragment_program) {
1954 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1955 return;
1956 }
1957 ctx->FragmentProgram.Callback = callback;
1958 ctx->FragmentProgram.CallbackData = data;
1959 break;
1960 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
1961 if (!ctx->Extensions.ARB_vertex_program &&
1962 !ctx->Extensions.NV_vertex_program) {
1963 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1964 return;
1965 }
1966 ctx->VertexProgram.Callback = callback;
1967 ctx->VertexProgram.CallbackData = data;
1968 break;
1969 default:
1970 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1971 return;
1972 }
1973}
1974
1975
1976/* XXX temporary */
Daniel Borca0a13ceb2005-02-14 08:01:59 +00001977GLAPI void GLAPIENTRY
Michal Krol2861e732004-03-29 11:09:34 +00001978glGetProgramRegisterfvMESA(GLenum target,
1979 GLsizei len, const GLubyte *registerName,
1980 GLfloat *v)
1981{
1982 _mesa_GetProgramRegisterfvMESA(target, len, registerName, v);
1983}
1984
1985
1986void
1987_mesa_GetProgramRegisterfvMESA(GLenum target,
1988 GLsizei len, const GLubyte *registerName,
1989 GLfloat *v)
1990{
1991 char reg[1000];
1992 GET_CURRENT_CONTEXT(ctx);
1993
1994 /* We _should_ be inside glBegin/glEnd */
1995#if 0
1996 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
1997 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA");
1998 return;
1999 }
2000#endif
2001
2002 /* make null-terminated copy of registerName */
2003 len = MIN2((unsigned int) len, sizeof(reg) - 1);
2004 _mesa_memcpy(reg, registerName, len);
2005 reg[len] = 0;
2006
2007 switch (target) {
Roland Scheideggere1e03b32006-03-03 15:03:04 +00002008 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
Michal Krol2861e732004-03-29 11:09:34 +00002009 if (!ctx->Extensions.ARB_vertex_program &&
2010 !ctx->Extensions.NV_vertex_program) {
2011 _mesa_error(ctx, GL_INVALID_ENUM,
2012 "glGetProgramRegisterfvMESA(target)");
2013 return;
2014 }
Brian Paul6d460af2004-04-23 14:16:46 +00002015 if (!ctx->VertexProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00002016 _mesa_error(ctx, GL_INVALID_OPERATION,
2017 "glGetProgramRegisterfvMESA");
2018 return;
2019 }
2020 /* GL_NV_vertex_program */
2021 if (reg[0] == 'R') {
2022 /* Temp register */
2023 GLint i = _mesa_atoi(reg + 1);
Brian Paul05051032005-11-01 04:36:33 +00002024 if (i >= (GLint)ctx->Const.VertexProgram.MaxTemps) {
Michal Krol2861e732004-03-29 11:09:34 +00002025 _mesa_error(ctx, GL_INVALID_VALUE,
2026 "glGetProgramRegisterfvMESA(registerName)");
2027 return;
2028 }
2029 COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
2030 }
2031 else if (reg[0] == 'v' && reg[1] == '[') {
2032 /* Vertex Input attribute */
2033 GLuint i;
Brian Paul05051032005-11-01 04:36:33 +00002034 for (i = 0; i < ctx->Const.VertexProgram.MaxAttribs; i++) {
Michal Krol2861e732004-03-29 11:09:34 +00002035 const char *name = _mesa_nv_vertex_input_register_name(i);
2036 char number[10];
Brian Paulaa206952005-09-16 18:14:24 +00002037 _mesa_sprintf(number, "%d", i);
Michal Krol2861e732004-03-29 11:09:34 +00002038 if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
2039 _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
2040 COPY_4V(v, ctx->VertexProgram.Inputs[i]);
2041 return;
2042 }
2043 }
2044 _mesa_error(ctx, GL_INVALID_VALUE,
2045 "glGetProgramRegisterfvMESA(registerName)");
2046 return;
2047 }
2048 else if (reg[0] == 'o' && reg[1] == '[') {
2049 /* Vertex output attribute */
2050 }
2051 /* GL_ARB_vertex_program */
2052 else if (_mesa_strncmp(reg, "vertex.", 7) == 0) {
2053
2054 }
2055 else {
2056 _mesa_error(ctx, GL_INVALID_VALUE,
2057 "glGetProgramRegisterfvMESA(registerName)");
2058 return;
2059 }
2060 break;
2061 case GL_FRAGMENT_PROGRAM_ARB:
2062 if (!ctx->Extensions.ARB_fragment_program) {
2063 _mesa_error(ctx, GL_INVALID_ENUM,
2064 "glGetProgramRegisterfvMESA(target)");
2065 return;
2066 }
Brian Paul6d460af2004-04-23 14:16:46 +00002067 if (!ctx->FragmentProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00002068 _mesa_error(ctx, GL_INVALID_OPERATION,
2069 "glGetProgramRegisterfvMESA");
2070 return;
2071 }
2072 /* XXX to do */
2073 break;
2074 case GL_FRAGMENT_PROGRAM_NV:
2075 if (!ctx->Extensions.NV_fragment_program) {
2076 _mesa_error(ctx, GL_INVALID_ENUM,
2077 "glGetProgramRegisterfvMESA(target)");
2078 return;
2079 }
Brian Paul6d460af2004-04-23 14:16:46 +00002080 if (!ctx->FragmentProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00002081 _mesa_error(ctx, GL_INVALID_OPERATION,
2082 "glGetProgramRegisterfvMESA");
2083 return;
2084 }
2085 if (reg[0] == 'R') {
2086 /* Temp register */
2087 GLint i = _mesa_atoi(reg + 1);
Brian Paul05051032005-11-01 04:36:33 +00002088 if (i >= (GLint)ctx->Const.FragmentProgram.MaxTemps) {
Michal Krol2861e732004-03-29 11:09:34 +00002089 _mesa_error(ctx, GL_INVALID_VALUE,
2090 "glGetProgramRegisterfvMESA(registerName)");
2091 return;
2092 }
2093 COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
2094 }
2095 else if (reg[0] == 'f' && reg[1] == '[') {
2096 /* Fragment input attribute */
2097 GLuint i;
Brian Paul05051032005-11-01 04:36:33 +00002098 for (i = 0; i < ctx->Const.FragmentProgram.MaxAttribs; i++) {
Michal Krol2861e732004-03-29 11:09:34 +00002099 const char *name = _mesa_nv_fragment_input_register_name(i);
2100 if (_mesa_strncmp(reg + 2, name, 4) == 0) {
2101 COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
2102 return;
2103 }
2104 }
2105 _mesa_error(ctx, GL_INVALID_VALUE,
2106 "glGetProgramRegisterfvMESA(registerName)");
2107 return;
2108 }
2109 else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
2110 /* Fragment output color */
Brian Paul90ebb582005-11-02 18:06:12 +00002111 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLR]);
Michal Krol2861e732004-03-29 11:09:34 +00002112 }
2113 else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
2114 /* Fragment output color */
Brian Paul90ebb582005-11-02 18:06:12 +00002115 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLH]);
Michal Krol2861e732004-03-29 11:09:34 +00002116 }
2117 else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
2118 /* Fragment output depth */
Brian Paul90ebb582005-11-02 18:06:12 +00002119 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_DEPR]);
Michal Krol2861e732004-03-29 11:09:34 +00002120 }
2121 else {
2122 /* try user-defined identifiers */
2123 const GLfloat *value = _mesa_lookup_parameter_value(
Brian Paulde997602005-11-12 17:53:14 +00002124 ctx->FragmentProgram.Current->Base.Parameters, -1, reg);
Michal Krol2861e732004-03-29 11:09:34 +00002125 if (value) {
2126 COPY_4V(v, value);
2127 }
2128 else {
2129 _mesa_error(ctx, GL_INVALID_VALUE,
2130 "glGetProgramRegisterfvMESA(registerName)");
2131 return;
2132 }
2133 }
2134 break;
2135 default:
2136 _mesa_error(ctx, GL_INVALID_ENUM,
2137 "glGetProgramRegisterfvMESA(target)");
2138 return;
2139 }
2140
2141}