blob: 70a9ced7a669c699365b328d6412a1fd22e71c3e [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul765f1a12004-09-14 22:28:27 +00003 * Version: 6.2
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"
Brian Paul575700f2004-12-16 03:07:18 +000042#include "nvvertprog.h"
Roland Scheideggerf519a772005-09-02 01:11:53 +000043#include "atifragshader.h"
Michal Krol2861e732004-03-29 11:09:34 +000044
45
46/**********************************************************************/
47/* Utility functions */
48/**********************************************************************/
49
50
Brian Paul765f1a12004-09-14 22:28:27 +000051/* A pointer to this dummy program is put into the hash table when
52 * glGenPrograms is called.
53 */
Brian Paul9ca83922004-10-02 15:16:59 +000054struct program _mesa_DummyProgram;
Brian Paul765f1a12004-09-14 22:28:27 +000055
56
Michal Krol2861e732004-03-29 11:09:34 +000057/**
Brian Paul21841f02004-08-14 14:28:11 +000058 * Init context's vertex/fragment program state
Michal Krol2861e732004-03-29 11:09:34 +000059 */
60void
61_mesa_init_program(GLcontext *ctx)
62{
63 GLuint i;
64
65 ctx->Program.ErrorPos = -1;
66 ctx->Program.ErrorString = _mesa_strdup("");
67
68#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
69 ctx->VertexProgram.Enabled = GL_FALSE;
70 ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
71 ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +000072 ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram;
73 assert(ctx->VertexProgram.Current);
74 ctx->VertexProgram.Current->Base.RefCount++;
75 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
76 ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
77 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
78 }
79#endif
80
81#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
82 ctx->FragmentProgram.Enabled = GL_FALSE;
83 ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram;
84 assert(ctx->FragmentProgram.Current);
85 ctx->FragmentProgram.Current->Base.RefCount++;
86#endif
Dave Airlie7f752fe2004-12-19 03:06:59 +000087
88#if FEATURE_ATI_fragment_shader
89 ctx->ATIFragmentShader.Enabled = GL_FALSE;
90 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
91 assert(ctx->ATIFragmentShader.Current);
92 ctx->ATIFragmentShader.Current->Base.RefCount++;
93#endif
Michal Krol2861e732004-03-29 11:09:34 +000094}
95
96
97/**
Brian Paul21841f02004-08-14 14:28:11 +000098 * Free a context's vertex/fragment program state
99 */
100void
101_mesa_free_program_data(GLcontext *ctx)
102{
103#if FEATURE_NV_vertex_program
104 if (ctx->VertexProgram.Current) {
105 ctx->VertexProgram.Current->Base.RefCount--;
106 if (ctx->VertexProgram.Current->Base.RefCount <= 0)
107 ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
108 }
109#endif
110#if FEATURE_NV_fragment_program
111 if (ctx->FragmentProgram.Current) {
112 ctx->FragmentProgram.Current->Base.RefCount--;
113 if (ctx->FragmentProgram.Current->Base.RefCount <= 0)
114 ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
115 }
116#endif
Dave Airlie7f752fe2004-12-19 03:06:59 +0000117#if FEATURE_ATI_fragment_shader
118 if (ctx->ATIFragmentShader.Current) {
119 ctx->ATIFragmentShader.Current->Base.RefCount--;
120 if (ctx->ATIFragmentShader.Current->Base.RefCount <= 0)
121 ctx->Driver.DeleteProgram(ctx, &(ctx->ATIFragmentShader.Current->Base));
122 }
123#endif
Brian Paul21841f02004-08-14 14:28:11 +0000124 _mesa_free((void *) ctx->Program.ErrorString);
125}
126
127
128
129
130/**
Michal Krol2861e732004-03-29 11:09:34 +0000131 * Set the vertex/fragment program error state (position and error string).
132 * This is generally called from within the parsers.
133 */
134void
135_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
136{
137 ctx->Program.ErrorPos = pos;
138 _mesa_free((void *) ctx->Program.ErrorString);
139 if (!string)
140 string = "";
141 ctx->Program.ErrorString = _mesa_strdup(string);
142}
143
144
145/**
146 * Find the line number and column for 'pos' within 'string'.
147 * Return a copy of the line which contains 'pos'. Free the line with
148 * _mesa_free().
149 * \param string the program string
150 * \param pos the position within the string
151 * \param line returns the line number corresponding to 'pos'.
152 * \param col returns the column number corresponding to 'pos'.
153 * \return copy of the line containing 'pos'.
154 */
155const GLubyte *
156_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
157 GLint *line, GLint *col)
158{
159 const GLubyte *lineStart = string;
160 const GLubyte *p = string;
161 GLubyte *s;
162 int len;
163
164 *line = 1;
165
166 while (p != pos) {
167 if (*p == (GLubyte) '\n') {
168 (*line)++;
169 lineStart = p + 1;
170 }
171 p++;
172 }
173
174 *col = (pos - lineStart) + 1;
175
176 /* return copy of this line */
177 while (*p != 0 && *p != '\n')
178 p++;
179 len = p - lineStart;
180 s = (GLubyte *) _mesa_malloc(len + 1);
181 _mesa_memcpy(s, lineStart, len);
182 s[len] = 0;
183
184 return s;
185}
186
187
Brian Paul765f1a12004-09-14 22:28:27 +0000188/**
189 * Initialize a new vertex/fragment program object.
190 */
191static struct program *
192_mesa_init_program_struct( GLcontext *ctx, struct program *prog,
193 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000194{
Brian Paula6c423d2004-08-25 15:59:48 +0000195 (void) ctx;
Michal Krol2861e732004-03-29 11:09:34 +0000196 if (prog) {
197 prog->Id = id;
198 prog->Target = target;
199 prog->Resident = GL_TRUE;
200 prog->RefCount = 1;
201 }
202
203 return prog;
204}
205
Brian Paul765f1a12004-09-14 22:28:27 +0000206
207/**
208 * Initialize a new fragment program object.
209 */
210struct program *
211_mesa_init_fragment_program( GLcontext *ctx, struct fragment_program *prog,
212 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000213{
214 if (prog)
215 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
216 else
217 return NULL;
218}
219
Brian Paul765f1a12004-09-14 22:28:27 +0000220
221/**
222 * Initialize a new vertex program object.
223 */
224struct program *
225_mesa_init_vertex_program( GLcontext *ctx, struct vertex_program *prog,
226 GLenum target, GLuint id)
Michal Krol2861e732004-03-29 11:09:34 +0000227{
228 if (prog)
229 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
230 else
231 return NULL;
232}
233
Dave Airlie7f752fe2004-12-19 03:06:59 +0000234/**
235 * Initialize a new ATI fragment shader object.
236 */
237struct program *
Brian Paulcdb65412005-01-11 15:56:47 +0000238_mesa_init_ati_fragment_shader( GLcontext *ctx,
239 struct ati_fragment_shader *prog,
240 GLenum target, GLuint id )
Dave Airlie7f752fe2004-12-19 03:06:59 +0000241{
242 if (prog)
243 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
244 else
245 return NULL;
246}
247
248
Michal Krol2861e732004-03-29 11:09:34 +0000249
250/**
251 * Allocate and initialize a new fragment/vertex program object but
252 * don't put it into the program hash table. Called via
253 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
254 * device driver function to implement OO deriviation with additional
255 * types not understood by this function.
256 *
257 * \param ctx context
258 * \param id program id/number
259 * \param target program target/type
260 * \return pointer to new program object
261 */
262struct program *
263_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
264{
265 switch (target) {
266 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
267 return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program),
268 target, id );
Michal Krol2861e732004-03-29 11:09:34 +0000269 case GL_FRAGMENT_PROGRAM_NV:
270 case GL_FRAGMENT_PROGRAM_ARB:
271 return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program),
272 target, id );
Dave Airlie7f752fe2004-12-19 03:06:59 +0000273 case GL_FRAGMENT_SHADER_ATI:
274 return _mesa_init_ati_fragment_shader( ctx, CALLOC_STRUCT(ati_fragment_shader),
275 target, id );
276
Michal Krol2861e732004-03-29 11:09:34 +0000277 default:
278 _mesa_problem(ctx, "bad target in _mesa_new_program");
279 return NULL;
280 }
281}
282
283
284/**
285 * Delete a program and remove it from the hash table, ignoring the
286 * reference count.
287 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
288 * by a device driver function.
289 */
290void
291_mesa_delete_program(GLcontext *ctx, struct program *prog)
292{
Brian Paula6c423d2004-08-25 15:59:48 +0000293 (void) ctx;
Michal Krol2861e732004-03-29 11:09:34 +0000294 ASSERT(prog);
295
296 if (prog->String)
297 _mesa_free(prog->String);
298 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
299 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
300 struct vertex_program *vprog = (struct vertex_program *) prog;
Brian Paul575700f2004-12-16 03:07:18 +0000301 if (vprog->Instructions) {
302 GLuint i;
303 for (i = 0; i < vprog->Base.NumInstructions; i++) {
304 if (vprog->Instructions[i].Data)
305 _mesa_free(vprog->Instructions[i].Data);
306 }
Michal Krol2861e732004-03-29 11:09:34 +0000307 _mesa_free(vprog->Instructions);
Brian Paul575700f2004-12-16 03:07:18 +0000308 }
Brian Paul21841f02004-08-14 14:28:11 +0000309 if (vprog->Parameters)
310 _mesa_free_parameter_list(vprog->Parameters);
Michal Krol2861e732004-03-29 11:09:34 +0000311 }
312 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
313 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
314 struct fragment_program *fprog = (struct fragment_program *) prog;
Brian Paul2a5afe32004-12-18 16:18:00 +0000315 if (fprog->Instructions) {
316 GLuint i;
317 for (i = 0; i < fprog->Base.NumInstructions; i++) {
318 if (fprog->Instructions[i].Data)
319 _mesa_free(fprog->Instructions[i].Data);
320 }
Michal Krol2861e732004-03-29 11:09:34 +0000321 _mesa_free(fprog->Instructions);
Brian Paul2a5afe32004-12-18 16:18:00 +0000322 }
Brian Paul21841f02004-08-14 14:28:11 +0000323 if (fprog->Parameters)
Michal Krol2861e732004-03-29 11:09:34 +0000324 _mesa_free_parameter_list(fprog->Parameters);
Michal Krol2861e732004-03-29 11:09:34 +0000325 }
Dave Airlie7f752fe2004-12-19 03:06:59 +0000326 else if (prog->Target == GL_FRAGMENT_SHADER_ATI) {
327 struct ati_fragment_shader *atifs = (struct ati_fragment_shader *)prog;
Roland Scheideggerf519a772005-09-02 01:11:53 +0000328 GLuint i;
329 for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
330 if (atifs->Instructions[i])
331 _mesa_free(atifs->Instructions[i]);
332 if (atifs->SetupInst[i])
333 _mesa_free(atifs->SetupInst[i]);
334 }
Dave Airlie7f752fe2004-12-19 03:06:59 +0000335 }
336
Michal Krol2861e732004-03-29 11:09:34 +0000337 _mesa_free(prog);
338}
339
340
341
342/**********************************************************************/
343/* Program parameter functions */
344/**********************************************************************/
345
346struct program_parameter_list *
347_mesa_new_parameter_list(void)
348{
349 return (struct program_parameter_list *)
350 _mesa_calloc(sizeof(struct program_parameter_list));
351}
352
353
354/**
355 * Free a parameter list and all its parameters
356 */
357void
358_mesa_free_parameter_list(struct program_parameter_list *paramList)
359{
360 _mesa_free_parameters(paramList);
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000361 _mesa_free(paramList->Parameters);
Keith Whitwell9899f582005-06-08 21:57:45 +0000362 if (paramList->ParameterValues)
363 ALIGN_FREE(paramList->ParameterValues);
Michal Krol2861e732004-03-29 11:09:34 +0000364 _mesa_free(paramList);
365}
366
367
368/**
369 * Free all the parameters in the given list, but don't free the
370 * paramList structure itself.
371 */
372void
373_mesa_free_parameters(struct program_parameter_list *paramList)
374{
375 GLuint i;
376 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000377 if (paramList->Parameters[i].Name)
378 _mesa_free((void *) paramList->Parameters[i].Name);
Michal Krol2861e732004-03-29 11:09:34 +0000379 }
Michal Krol2861e732004-03-29 11:09:34 +0000380 paramList->NumParameters = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000381}
382
383
384/**
385 * Helper function used by the functions below.
386 */
387static GLint
388add_parameter(struct program_parameter_list *paramList,
389 const char *name, const GLfloat values[4],
390 enum parameter_type type)
391{
392 const GLuint n = paramList->NumParameters;
393
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000394 if (n == paramList->Size) {
Keith Whitwell9899f582005-06-08 21:57:45 +0000395 GLfloat (*tmp)[4];
396
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000397 paramList->Size *= 2;
398 if (!paramList->Size)
Keith Whitwell9899f582005-06-08 21:57:45 +0000399 paramList->Size = 8;
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000400
401 paramList->Parameters = (struct program_parameter *)
402 _mesa_realloc(paramList->Parameters,
403 n * sizeof(struct program_parameter),
404 paramList->Size * sizeof(struct program_parameter));
Keith Whitwell9899f582005-06-08 21:57:45 +0000405
406 tmp = paramList->ParameterValues;
407 paramList->ParameterValues = ALIGN_MALLOC(paramList->Size * 4 * sizeof(GLfloat), 16);
408 if (tmp) {
409 _mesa_memcpy(paramList->ParameterValues, tmp,
410 n * 4 * sizeof(GLfloat));
411 ALIGN_FREE(tmp);
412 }
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000413 }
Keith Whitwell7c26b612005-04-21 14:46:57 +0000414
415 if (!paramList->Parameters ||
416 !paramList->ParameterValues) {
Michal Krol2861e732004-03-29 11:09:34 +0000417 /* out of memory */
418 paramList->NumParameters = 0;
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000419 paramList->Size = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000420 return -1;
421 }
422 else {
423 paramList->NumParameters = n + 1;
Keith Whitwella42fe192005-05-10 18:22:19 +0000424
425 _mesa_memset(&paramList->Parameters[n], 0,
426 sizeof(struct program_parameter));
427
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000428 paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
Michal Krol2861e732004-03-29 11:09:34 +0000429 paramList->Parameters[n].Type = type;
430 if (values)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000431 COPY_4V(paramList->ParameterValues[n], values);
Michal Krol2861e732004-03-29 11:09:34 +0000432 return (GLint) n;
433 }
434}
435
436
437/**
438 * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
439 * \return index of the new entry in the parameter list
440 */
441GLint
442_mesa_add_named_parameter(struct program_parameter_list *paramList,
443 const char *name, const GLfloat values[4])
444{
445 return add_parameter(paramList, name, values, NAMED_PARAMETER);
446}
447
448
449/**
450 * Add a new unnamed constant to the parameter list.
451 * \param paramList - the parameter list
452 * \param values - four float values
453 * \return index of the new parameter.
454 */
455GLint
456_mesa_add_named_constant(struct program_parameter_list *paramList,
457 const char *name, const GLfloat values[4])
458{
459 return add_parameter(paramList, name, values, CONSTANT);
460}
461
462
463/**
464 * Add a new unnamed constant to the parameter list.
465 * \param paramList - the parameter list
466 * \param values - four float values
467 * \return index of the new parameter.
468 */
469GLint
470_mesa_add_unnamed_constant(struct program_parameter_list *paramList,
471 const GLfloat values[4])
472{
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000473 return add_parameter(paramList, NULL, values, CONSTANT);
Michal Krol2861e732004-03-29 11:09:34 +0000474}
475
476
477/**
478 * Add a new state reference to the parameter list.
479 * \param paramList - the parameter list
480 * \param state - an array of 6 state tokens
481 *
482 * \return index of the new parameter.
483 */
484GLint
485_mesa_add_state_reference(struct program_parameter_list *paramList,
486 GLint *stateTokens)
487{
488 /* XXX Should we parse <stateString> here and produce the parameter's
489 * list of STATE_* tokens here, or in the parser?
490 */
491 GLint a, idx;
492
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000493 idx = add_parameter(paramList, NULL, NULL, STATE);
Michal Krol2861e732004-03-29 11:09:34 +0000494
495 for (a=0; a<6; a++)
496 paramList->Parameters[idx].StateIndexes[a] = (enum state_index) stateTokens[a];
497
498 return idx;
499}
500
501
502/**
503 * Lookup a parameter value by name in the given parameter list.
504 * \return pointer to the float[4] values.
505 */
506GLfloat *
507_mesa_lookup_parameter_value(struct program_parameter_list *paramList,
508 GLsizei nameLen, const char *name)
509{
510 GLuint i;
511
512 if (!paramList)
513 return NULL;
514
515 if (nameLen == -1) {
516 /* name is null-terminated */
517 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000518 if (paramList->Parameters[i].Name &&
519 _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000520 return paramList->ParameterValues[i];
Michal Krol2861e732004-03-29 11:09:34 +0000521 }
522 }
523 else {
524 /* name is not null-terminated, use nameLen */
525 for (i = 0; i < paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000526 if (paramList->Parameters[i].Name &&
527 _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
Michal Krol2861e732004-03-29 11:09:34 +0000528 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
Keith Whitwell7c26b612005-04-21 14:46:57 +0000529 return paramList->ParameterValues[i];
Michal Krol2861e732004-03-29 11:09:34 +0000530 }
531 }
532 return NULL;
533}
534
535
536/**
537 * Lookup a parameter index by name in the given parameter list.
538 * \return index of parameter in the list.
539 */
540GLint
541_mesa_lookup_parameter_index(struct program_parameter_list *paramList,
542 GLsizei nameLen, const char *name)
543{
544 GLint i;
545
546 if (!paramList)
547 return -1;
548
549 if (nameLen == -1) {
550 /* name is null-terminated */
551 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000552 if (paramList->Parameters[i].Name &&
553 _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
Michal Krol2861e732004-03-29 11:09:34 +0000554 return i;
555 }
556 }
557 else {
558 /* name is not null-terminated, use nameLen */
559 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
Keith Whitwellf29f2fc2005-05-10 13:56:23 +0000560 if (paramList->Parameters[i].Name &&
561 _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
Michal Krol2861e732004-03-29 11:09:34 +0000562 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
563 return i;
564 }
565 }
566 return -1;
567}
568
569
570/**
571 * Use the list of tokens in the state[] array to find global GL state
572 * and return it in <value>. Usually, four values are returned in <value>
573 * but matrix queries may return as many as 16 values.
574 * This function is used for ARB vertex/fragment programs.
575 * The program parser will produce the state[] values.
576 */
577static void
578_mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
579 GLfloat *value)
580{
581 switch (state[0]) {
582 case STATE_MATERIAL:
583 {
584 /* state[1] is either 0=front or 1=back side */
585 const GLuint face = (GLuint) state[1];
586 /* state[2] is the material attribute */
587 switch (state[2]) {
588 case STATE_AMBIENT:
589 if (face == 0)
590 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
591 else
592 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
593 return;
594 case STATE_DIFFUSE:
595 if (face == 0)
596 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
597 else
598 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
599 return;
600 case STATE_SPECULAR:
601 if (face == 0)
602 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
603 else
604 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
605 return;
606 case STATE_EMISSION:
607 if (face == 0)
608 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
609 else
610 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
611 return;
612 case STATE_SHININESS:
613 if (face == 0)
614 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
615 else
616 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
617 value[1] = 0.0F;
618 value[2] = 0.0F;
619 value[3] = 1.0F;
620 return;
621 default:
622 _mesa_problem(ctx, "Invalid material state in fetch_state");
623 return;
624 }
Alan Hourihane22ae6332004-12-02 13:29:40 +0000625 }
Michal Krol2861e732004-03-29 11:09:34 +0000626 case STATE_LIGHT:
627 {
628 /* state[1] is the light number */
629 const GLuint ln = (GLuint) state[1];
630 /* state[2] is the light attribute */
631 switch (state[2]) {
632 case STATE_AMBIENT:
633 COPY_4V(value, ctx->Light.Light[ln].Ambient);
634 return;
635 case STATE_DIFFUSE:
636 COPY_4V(value, ctx->Light.Light[ln].Diffuse);
637 return;
638 case STATE_SPECULAR:
639 COPY_4V(value, ctx->Light.Light[ln].Specular);
640 return;
641 case STATE_POSITION:
642 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
643 return;
644 case STATE_ATTENUATION:
645 value[0] = ctx->Light.Light[ln].ConstantAttenuation;
646 value[1] = ctx->Light.Light[ln].LinearAttenuation;
647 value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
648 value[3] = ctx->Light.Light[ln].SpotExponent;
649 return;
650 case STATE_SPOT_DIRECTION:
Brian Paul52bf0052005-04-20 23:47:03 +0000651 COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
652 value[3] = ctx->Light.Light[ln]._CosCutoff;
Michal Krol2861e732004-03-29 11:09:34 +0000653 return;
654 case STATE_HALF:
655 {
656 GLfloat eye_z[] = {0, 0, 1};
657
658 /* Compute infinite half angle vector:
659 * half-vector = light_position + (0, 0, 1)
660 * and then normalize. w = 0
Keith Whitwell7c26b612005-04-21 14:46:57 +0000661 *
662 * light.EyePosition.w should be 0 for infinite lights.
Michal Krol2861e732004-03-29 11:09:34 +0000663 */
Keith Whitwell7c26b612005-04-21 14:46:57 +0000664 ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
665 NORMALIZE_3FV(value);
666 value[3] = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000667 }
668 return;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000669 case STATE_POSITION_NORMALIZED:
670 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
671 NORMALIZE_3FV( value );
672 return;
Michal Krol2861e732004-03-29 11:09:34 +0000673 default:
674 _mesa_problem(ctx, "Invalid light state in fetch_state");
675 return;
676 }
677 }
Michal Krol2861e732004-03-29 11:09:34 +0000678 case STATE_LIGHTMODEL_AMBIENT:
679 COPY_4V(value, ctx->Light.Model.Ambient);
680 return;
681 case STATE_LIGHTMODEL_SCENECOLOR:
682 if (state[1] == 0) {
683 /* front */
684 GLint i;
Keith Whitwell78803b22005-04-15 12:57:23 +0000685 for (i = 0; i < 3; i++) {
Michal Krol2861e732004-03-29 11:09:34 +0000686 value[i] = ctx->Light.Model.Ambient[i]
687 * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
688 + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
689 }
Keith Whitwell78803b22005-04-15 12:57:23 +0000690 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
Michal Krol2861e732004-03-29 11:09:34 +0000691 }
692 else {
693 /* back */
694 GLint i;
Keith Whitwell78803b22005-04-15 12:57:23 +0000695 for (i = 0; i < 3; i++) {
Michal Krol2861e732004-03-29 11:09:34 +0000696 value[i] = ctx->Light.Model.Ambient[i]
697 * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
698 + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
699 }
Keith Whitwell78803b22005-04-15 12:57:23 +0000700 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
Michal Krol2861e732004-03-29 11:09:34 +0000701 }
702 return;
703 case STATE_LIGHTPROD:
704 {
705 const GLuint ln = (GLuint) state[1];
706 const GLuint face = (GLuint) state[2];
707 GLint i;
708 ASSERT(face == 0 || face == 1);
709 switch (state[3]) {
710 case STATE_AMBIENT:
711 for (i = 0; i < 3; i++) {
712 value[i] = ctx->Light.Light[ln].Ambient[i] *
713 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
714 }
715 /* [3] = material alpha */
716 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
717 return;
718 case STATE_DIFFUSE:
719 for (i = 0; i < 3; i++) {
720 value[i] = ctx->Light.Light[ln].Diffuse[i] *
721 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
722 }
723 /* [3] = material alpha */
724 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
725 return;
726 case STATE_SPECULAR:
727 for (i = 0; i < 3; i++) {
728 value[i] = ctx->Light.Light[ln].Specular[i] *
729 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
730 }
731 /* [3] = material alpha */
732 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
733 return;
734 default:
735 _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
736 return;
737 }
738 }
Michal Krol2861e732004-03-29 11:09:34 +0000739 case STATE_TEXGEN:
740 {
741 /* state[1] is the texture unit */
742 const GLuint unit = (GLuint) state[1];
743 /* state[2] is the texgen attribute */
744 switch (state[2]) {
745 case STATE_TEXGEN_EYE_S:
746 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
747 return;
748 case STATE_TEXGEN_EYE_T:
749 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
750 return;
751 case STATE_TEXGEN_EYE_R:
752 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
753 return;
754 case STATE_TEXGEN_EYE_Q:
755 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
756 return;
757 case STATE_TEXGEN_OBJECT_S:
758 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
759 return;
760 case STATE_TEXGEN_OBJECT_T:
761 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
762 return;
763 case STATE_TEXGEN_OBJECT_R:
764 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
765 return;
766 case STATE_TEXGEN_OBJECT_Q:
767 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
768 return;
769 default:
770 _mesa_problem(ctx, "Invalid texgen state in fetch_state");
771 return;
772 }
773 }
Michal Krol2861e732004-03-29 11:09:34 +0000774 case STATE_TEXENV_COLOR:
775 {
776 /* state[1] is the texture unit */
777 const GLuint unit = (GLuint) state[1];
778 COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
779 }
780 return;
781 case STATE_FOG_COLOR:
782 COPY_4V(value, ctx->Fog.Color);
783 return;
784 case STATE_FOG_PARAMS:
785 value[0] = ctx->Fog.Density;
786 value[1] = ctx->Fog.Start;
787 value[2] = ctx->Fog.End;
788 value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
789 return;
790 case STATE_CLIPPLANE:
791 {
792 const GLuint plane = (GLuint) state[1];
793 COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
794 }
795 return;
796 case STATE_POINT_SIZE:
797 value[0] = ctx->Point.Size;
798 value[1] = ctx->Point.MinSize;
799 value[2] = ctx->Point.MaxSize;
800 value[3] = ctx->Point.Threshold;
801 return;
802 case STATE_POINT_ATTENUATION:
803 value[0] = ctx->Point.Params[0];
804 value[1] = ctx->Point.Params[1];
805 value[2] = ctx->Point.Params[2];
806 value[3] = 1.0F;
807 return;
808 case STATE_MATRIX:
809 {
810 /* state[1] = modelview, projection, texture, etc. */
811 /* state[2] = which texture matrix or program matrix */
812 /* state[3] = first column to fetch */
813 /* state[4] = last column to fetch */
814 /* state[5] = transpose, inverse or invtrans */
815
816 const GLmatrix *matrix;
817 const enum state_index mat = state[1];
818 const GLuint index = (GLuint) state[2];
819 const GLuint first = (GLuint) state[3];
820 const GLuint last = (GLuint) state[4];
821 const enum state_index modifier = state[5];
822 const GLfloat *m;
823 GLuint row, i;
824 if (mat == STATE_MODELVIEW) {
825 matrix = ctx->ModelviewMatrixStack.Top;
826 }
827 else if (mat == STATE_PROJECTION) {
828 matrix = ctx->ProjectionMatrixStack.Top;
829 }
830 else if (mat == STATE_MVP) {
831 matrix = &ctx->_ModelProjectMatrix;
832 }
833 else if (mat == STATE_TEXTURE) {
834 matrix = ctx->TextureMatrixStack[index].Top;
835 }
836 else if (mat == STATE_PROGRAM) {
837 matrix = ctx->ProgramMatrixStack[index].Top;
838 }
839 else {
840 _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
841 return;
842 }
843 if (modifier == STATE_MATRIX_INVERSE ||
844 modifier == STATE_MATRIX_INVTRANS) {
Keith Whitwell78803b22005-04-15 12:57:23 +0000845 /* Be sure inverse is up to date:
846 */
Jouk Jansen49b1d952005-04-18 13:05:24 +0000847 _math_matrix_analyse( (GLmatrix*) matrix );
Michal Krol2861e732004-03-29 11:09:34 +0000848 m = matrix->inv;
849 }
850 else {
851 m = matrix->m;
852 }
853 if (modifier == STATE_MATRIX_TRANSPOSE ||
854 modifier == STATE_MATRIX_INVTRANS) {
855 for (i = 0, row = first; row <= last; row++) {
856 value[i++] = m[row * 4 + 0];
857 value[i++] = m[row * 4 + 1];
858 value[i++] = m[row * 4 + 2];
859 value[i++] = m[row * 4 + 3];
860 }
861 }
862 else {
863 for (i = 0, row = first; row <= last; row++) {
864 value[i++] = m[row + 0];
865 value[i++] = m[row + 4];
866 value[i++] = m[row + 8];
867 value[i++] = m[row + 12];
868 }
869 }
870 }
871 return;
872 case STATE_DEPTH_RANGE:
Brian Paul824fdf02004-06-29 00:00:06 +0000873 value[0] = ctx->Viewport.Near; /* near */
874 value[1] = ctx->Viewport.Far; /* far */
875 value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
876 value[3] = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000877 return;
878 case STATE_FRAGMENT_PROGRAM:
879 {
880 /* state[1] = {STATE_ENV, STATE_LOCAL} */
881 /* state[2] = parameter index */
Brian Paul824fdf02004-06-29 00:00:06 +0000882 const int idx = (int) state[2];
Michal Krol2861e732004-03-29 11:09:34 +0000883 switch (state[1]) {
884 case STATE_ENV:
Brian Paul824fdf02004-06-29 00:00:06 +0000885 COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
Michal Krol2861e732004-03-29 11:09:34 +0000886 break;
Michal Krol2861e732004-03-29 11:09:34 +0000887 case STATE_LOCAL:
888 COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
Brian Paul824fdf02004-06-29 00:00:06 +0000889 break;
Michal Krol2861e732004-03-29 11:09:34 +0000890 default:
891 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
892 return;
Brian Paul824fdf02004-06-29 00:00:06 +0000893 }
894 }
Michal Krol2861e732004-03-29 11:09:34 +0000895 return;
896
897 case STATE_VERTEX_PROGRAM:
Brian Paul824fdf02004-06-29 00:00:06 +0000898 {
Michal Krol2861e732004-03-29 11:09:34 +0000899 /* state[1] = {STATE_ENV, STATE_LOCAL} */
900 /* state[2] = parameter index */
Brian Paul824fdf02004-06-29 00:00:06 +0000901 const int idx = (int) state[2];
Michal Krol2861e732004-03-29 11:09:34 +0000902 switch (state[1]) {
903 case STATE_ENV:
Brian Paul824fdf02004-06-29 00:00:06 +0000904 COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
Michal Krol2861e732004-03-29 11:09:34 +0000905 break;
Michal Krol2861e732004-03-29 11:09:34 +0000906 case STATE_LOCAL:
907 COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
Brian Paul824fdf02004-06-29 00:00:06 +0000908 break;
Michal Krol2861e732004-03-29 11:09:34 +0000909 default:
910 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
911 return;
Brian Paul824fdf02004-06-29 00:00:06 +0000912 }
913 }
Michal Krol2861e732004-03-29 11:09:34 +0000914 return;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000915
916 case STATE_INTERNAL:
917 {
918 switch (state[1]) {
919 case STATE_NORMAL_SCALE:
920 ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
921 break;
922 default:
923 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
924 return;
925 }
926 }
927 return;
928
Michal Krol2861e732004-03-29 11:09:34 +0000929 default:
Brian Paul824fdf02004-06-29 00:00:06 +0000930 _mesa_problem(ctx, "Invalid state in _mesa_fetch_state");
Michal Krol2861e732004-03-29 11:09:34 +0000931 return;
932 }
933}
934
935
936/**
937 * Loop over all the parameters in a parameter list. If the parameter
938 * is a GL state reference, look up the current value of that state
939 * variable and put it into the parameter's Value[4] array.
940 * This would be called at glBegin time when using a fragment program.
941 */
942void
943_mesa_load_state_parameters(GLcontext *ctx,
944 struct program_parameter_list *paramList)
945{
946 GLuint i;
947
948 if (!paramList)
949 return;
950
951 for (i = 0; i < paramList->NumParameters; i++) {
952 if (paramList->Parameters[i].Type == STATE) {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000953 _mesa_fetch_state(ctx,
954 paramList->Parameters[i].StateIndexes,
955 paramList->ParameterValues[i]);
Michal Krol2861e732004-03-29 11:09:34 +0000956 }
957 }
958}
959
960
961
962/**********************************************************************/
963/* API functions */
964/**********************************************************************/
965
966
967/**
968 * Bind a program (make it current)
969 * \note Called from the GL API dispatcher by both glBindProgramNV
970 * and glBindProgramARB.
971 */
972void GLAPIENTRY
973_mesa_BindProgram(GLenum target, GLuint id)
974{
975 struct program *prog;
976 GET_CURRENT_CONTEXT(ctx);
977 ASSERT_OUTSIDE_BEGIN_END(ctx);
978
979 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
980
981 if ((target == GL_VERTEX_PROGRAM_NV
982 && ctx->Extensions.NV_vertex_program) ||
983 (target == GL_VERTEX_PROGRAM_ARB
984 && ctx->Extensions.ARB_vertex_program)) {
Brian Paul765f1a12004-09-14 22:28:27 +0000985 /*** Vertex program binding ***/
986 struct vertex_program *curProg = ctx->VertexProgram.Current;
987 if (curProg->Base.Id == id) {
988 /* binding same program - no change */
Michal Krol2861e732004-03-29 11:09:34 +0000989 return;
Brian Paul765f1a12004-09-14 22:28:27 +0000990 }
991 if (curProg->Base.Id != 0) {
992 /* decrement refcount on previously bound vertex program */
993 curProg->Base.RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +0000994 /* and delete if refcount goes below one */
Brian Paul765f1a12004-09-14 22:28:27 +0000995 if (curProg->Base.RefCount <= 0) {
Brian Paulea2943e2005-01-20 04:02:02 +0000996 /* the program ID was already removed from the hash table */
Brian Paul765f1a12004-09-14 22:28:27 +0000997 ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
Michal Krol2861e732004-03-29 11:09:34 +0000998 }
999 }
1000 }
1001 else if ((target == GL_FRAGMENT_PROGRAM_NV
1002 && ctx->Extensions.NV_fragment_program) ||
1003 (target == GL_FRAGMENT_PROGRAM_ARB
1004 && ctx->Extensions.ARB_fragment_program)) {
Brian Paul765f1a12004-09-14 22:28:27 +00001005 /*** Fragment program binding ***/
1006 struct fragment_program *curProg = ctx->FragmentProgram.Current;
1007 if (curProg->Base.Id == id) {
1008 /* binding same program - no change */
Michal Krol2861e732004-03-29 11:09:34 +00001009 return;
Brian Paul765f1a12004-09-14 22:28:27 +00001010 }
1011 if (curProg->Base.Id != 0) {
1012 /* decrement refcount on previously bound fragment program */
1013 curProg->Base.RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +00001014 /* and delete if refcount goes below one */
Brian Paul765f1a12004-09-14 22:28:27 +00001015 if (curProg->Base.RefCount <= 0) {
Brian Paulea2943e2005-01-20 04:02:02 +00001016 /* the program ID was already removed from the hash table */
Brian Paul765f1a12004-09-14 22:28:27 +00001017 ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
Michal Krol2861e732004-03-29 11:09:34 +00001018 }
1019 }
1020 }
1021 else {
1022 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
1023 return;
1024 }
1025
1026 /* NOTE: binding to a non-existant program is not an error.
1027 * That's supposed to be caught in glBegin.
1028 */
1029 if (id == 0) {
Brian Paul765f1a12004-09-14 22:28:27 +00001030 /* Bind default program */
Michal Krol2861e732004-03-29 11:09:34 +00001031 prog = NULL;
1032 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
1033 prog = ctx->Shared->DefaultVertexProgram;
1034 else
1035 prog = ctx->Shared->DefaultFragmentProgram;
1036 }
1037 else {
Brian Paul765f1a12004-09-14 22:28:27 +00001038 /* Bind user program */
Michal Krol2861e732004-03-29 11:09:34 +00001039 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
Brian Paul9ca83922004-10-02 15:16:59 +00001040 if (!prog || prog == &_mesa_DummyProgram) {
Michal Krol2861e732004-03-29 11:09:34 +00001041 /* allocate a new program now */
1042 prog = ctx->Driver.NewProgram(ctx, target, id);
1043 if (!prog) {
1044 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
1045 return;
1046 }
Michal Krol2861e732004-03-29 11:09:34 +00001047 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
1048 }
Brian Paul765f1a12004-09-14 22:28:27 +00001049 else if (prog->Target != target) {
1050 _mesa_error(ctx, GL_INVALID_OPERATION,
1051 "glBindProgramNV/ARB(target mismatch)");
1052 return;
1053 }
Michal Krol2861e732004-03-29 11:09:34 +00001054 }
1055
1056 /* bind now */
1057 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
1058 ctx->VertexProgram.Current = (struct vertex_program *) prog;
1059 }
1060 else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
1061 ctx->FragmentProgram.Current = (struct fragment_program *) prog;
1062 }
1063
Brian Paul765f1a12004-09-14 22:28:27 +00001064 /* Never null pointers */
1065 ASSERT(ctx->VertexProgram.Current);
1066 ASSERT(ctx->FragmentProgram.Current);
1067
Michal Krol2861e732004-03-29 11:09:34 +00001068 if (prog)
1069 prog->RefCount++;
1070
1071 if (ctx->Driver.BindProgram)
1072 ctx->Driver.BindProgram(ctx, target, prog);
1073}
1074
1075
1076/**
1077 * Delete a list of programs.
1078 * \note Not compiled into display lists.
1079 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
1080 */
1081void GLAPIENTRY
1082_mesa_DeletePrograms(GLsizei n, const GLuint *ids)
1083{
1084 GLint i;
1085 GET_CURRENT_CONTEXT(ctx);
1086 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1087
1088 if (n < 0) {
1089 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
1090 return;
1091 }
1092
1093 for (i = 0; i < n; i++) {
1094 if (ids[i] != 0) {
1095 struct program *prog = (struct program *)
1096 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
Brian Paul9ca83922004-10-02 15:16:59 +00001097 if (prog == &_mesa_DummyProgram) {
Brian Paul765f1a12004-09-14 22:28:27 +00001098 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1099 }
1100 else if (prog) {
1101 /* Unbind program if necessary */
Michal Krol2861e732004-03-29 11:09:34 +00001102 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
1103 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
1104 if (ctx->VertexProgram.Current &&
1105 ctx->VertexProgram.Current->Base.Id == ids[i]) {
1106 /* unbind this currently bound program */
1107 _mesa_BindProgram(prog->Target, 0);
1108 }
1109 }
1110 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
1111 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
1112 if (ctx->FragmentProgram.Current &&
1113 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
1114 /* unbind this currently bound program */
1115 _mesa_BindProgram(prog->Target, 0);
1116 }
1117 }
1118 else {
1119 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
1120 return;
1121 }
Brian Paulea2943e2005-01-20 04:02:02 +00001122 /* The ID is immediately available for re-use now */
1123 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
1124 prog->RefCount--;
Michal Krol2861e732004-03-29 11:09:34 +00001125 if (prog->RefCount <= 0) {
1126 ctx->Driver.DeleteProgram(ctx, prog);
1127 }
1128 }
Michal Krol2861e732004-03-29 11:09:34 +00001129 }
1130 }
1131}
1132
1133
1134/**
1135 * Generate a list of new program identifiers.
1136 * \note Not compiled into display lists.
1137 * \note Called by both glGenProgramsNV and glGenProgramsARB.
1138 */
1139void GLAPIENTRY
1140_mesa_GenPrograms(GLsizei n, GLuint *ids)
1141{
1142 GLuint first;
1143 GLuint i;
1144 GET_CURRENT_CONTEXT(ctx);
1145 ASSERT_OUTSIDE_BEGIN_END(ctx);
1146
1147 if (n < 0) {
1148 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
1149 return;
1150 }
1151
1152 if (!ids)
1153 return;
1154
1155 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
1156
Brian Paul765f1a12004-09-14 22:28:27 +00001157 /* Insert pointer to dummy program as placeholder */
Michal Krol2861e732004-03-29 11:09:34 +00001158 for (i = 0; i < (GLuint) n; i++) {
Brian Paul9ca83922004-10-02 15:16:59 +00001159 _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
Michal Krol2861e732004-03-29 11:09:34 +00001160 }
1161
1162 /* Return the program names */
1163 for (i = 0; i < (GLuint) n; i++) {
1164 ids[i] = first + i;
1165 }
1166}
1167
1168
1169/**
Brian Paul765f1a12004-09-14 22:28:27 +00001170 * Determine if id names a vertex or fragment program.
Michal Krol2861e732004-03-29 11:09:34 +00001171 * \note Not compiled into display lists.
1172 * \note Called from both glIsProgramNV and glIsProgramARB.
1173 * \param id is the program identifier
1174 * \return GL_TRUE if id is a program, else GL_FALSE.
1175 */
1176GLboolean GLAPIENTRY
1177_mesa_IsProgram(GLuint id)
1178{
1179 GET_CURRENT_CONTEXT(ctx);
1180 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1181
1182 if (id == 0)
1183 return GL_FALSE;
1184
1185 if (_mesa_HashLookup(ctx->Shared->Programs, id))
1186 return GL_TRUE;
1187 else
1188 return GL_FALSE;
1189}
1190
1191
1192
1193/**********************************************************************/
1194/* GL_MESA_program_debug extension */
1195/**********************************************************************/
1196
1197
1198/* XXX temporary */
Daniel Borca0a13ceb2005-02-14 08:01:59 +00001199GLAPI void GLAPIENTRY
Michal Krol2861e732004-03-29 11:09:34 +00001200glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1201 GLvoid *data)
1202{
1203 _mesa_ProgramCallbackMESA(target, callback, data);
1204}
1205
1206
1207void
1208_mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1209 GLvoid *data)
1210{
1211 GET_CURRENT_CONTEXT(ctx);
1212
1213 switch (target) {
1214 case GL_FRAGMENT_PROGRAM_ARB:
1215 if (!ctx->Extensions.ARB_fragment_program) {
1216 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1217 return;
1218 }
1219 ctx->FragmentProgram.Callback = callback;
1220 ctx->FragmentProgram.CallbackData = data;
1221 break;
1222 case GL_FRAGMENT_PROGRAM_NV:
1223 if (!ctx->Extensions.NV_fragment_program) {
1224 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1225 return;
1226 }
1227 ctx->FragmentProgram.Callback = callback;
1228 ctx->FragmentProgram.CallbackData = data;
1229 break;
1230 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
1231 if (!ctx->Extensions.ARB_vertex_program &&
1232 !ctx->Extensions.NV_vertex_program) {
1233 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1234 return;
1235 }
1236 ctx->VertexProgram.Callback = callback;
1237 ctx->VertexProgram.CallbackData = data;
1238 break;
1239 default:
1240 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1241 return;
1242 }
1243}
1244
1245
1246/* XXX temporary */
Daniel Borca0a13ceb2005-02-14 08:01:59 +00001247GLAPI void GLAPIENTRY
Michal Krol2861e732004-03-29 11:09:34 +00001248glGetProgramRegisterfvMESA(GLenum target,
1249 GLsizei len, const GLubyte *registerName,
1250 GLfloat *v)
1251{
1252 _mesa_GetProgramRegisterfvMESA(target, len, registerName, v);
1253}
1254
1255
1256void
1257_mesa_GetProgramRegisterfvMESA(GLenum target,
1258 GLsizei len, const GLubyte *registerName,
1259 GLfloat *v)
1260{
1261 char reg[1000];
1262 GET_CURRENT_CONTEXT(ctx);
1263
1264 /* We _should_ be inside glBegin/glEnd */
1265#if 0
1266 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
1267 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA");
1268 return;
1269 }
1270#endif
1271
1272 /* make null-terminated copy of registerName */
1273 len = MIN2((unsigned int) len, sizeof(reg) - 1);
1274 _mesa_memcpy(reg, registerName, len);
1275 reg[len] = 0;
1276
1277 switch (target) {
1278 case GL_VERTEX_PROGRAM_NV:
1279 if (!ctx->Extensions.ARB_vertex_program &&
1280 !ctx->Extensions.NV_vertex_program) {
1281 _mesa_error(ctx, GL_INVALID_ENUM,
1282 "glGetProgramRegisterfvMESA(target)");
1283 return;
1284 }
Brian Paul6d460af2004-04-23 14:16:46 +00001285 if (!ctx->VertexProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00001286 _mesa_error(ctx, GL_INVALID_OPERATION,
1287 "glGetProgramRegisterfvMESA");
1288 return;
1289 }
1290 /* GL_NV_vertex_program */
1291 if (reg[0] == 'R') {
1292 /* Temp register */
1293 GLint i = _mesa_atoi(reg + 1);
1294 if (i >= (GLint)ctx->Const.MaxVertexProgramTemps) {
1295 _mesa_error(ctx, GL_INVALID_VALUE,
1296 "glGetProgramRegisterfvMESA(registerName)");
1297 return;
1298 }
1299 COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
1300 }
1301 else if (reg[0] == 'v' && reg[1] == '[') {
1302 /* Vertex Input attribute */
1303 GLuint i;
1304 for (i = 0; i < ctx->Const.MaxVertexProgramAttribs; i++) {
1305 const char *name = _mesa_nv_vertex_input_register_name(i);
1306 char number[10];
Brian Paulaa206952005-09-16 18:14:24 +00001307 _mesa_sprintf(number, "%d", i);
Michal Krol2861e732004-03-29 11:09:34 +00001308 if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
1309 _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
1310 COPY_4V(v, ctx->VertexProgram.Inputs[i]);
1311 return;
1312 }
1313 }
1314 _mesa_error(ctx, GL_INVALID_VALUE,
1315 "glGetProgramRegisterfvMESA(registerName)");
1316 return;
1317 }
1318 else if (reg[0] == 'o' && reg[1] == '[') {
1319 /* Vertex output attribute */
1320 }
1321 /* GL_ARB_vertex_program */
1322 else if (_mesa_strncmp(reg, "vertex.", 7) == 0) {
1323
1324 }
1325 else {
1326 _mesa_error(ctx, GL_INVALID_VALUE,
1327 "glGetProgramRegisterfvMESA(registerName)");
1328 return;
1329 }
1330 break;
1331 case GL_FRAGMENT_PROGRAM_ARB:
1332 if (!ctx->Extensions.ARB_fragment_program) {
1333 _mesa_error(ctx, GL_INVALID_ENUM,
1334 "glGetProgramRegisterfvMESA(target)");
1335 return;
1336 }
Brian Paul6d460af2004-04-23 14:16:46 +00001337 if (!ctx->FragmentProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00001338 _mesa_error(ctx, GL_INVALID_OPERATION,
1339 "glGetProgramRegisterfvMESA");
1340 return;
1341 }
1342 /* XXX to do */
1343 break;
1344 case GL_FRAGMENT_PROGRAM_NV:
1345 if (!ctx->Extensions.NV_fragment_program) {
1346 _mesa_error(ctx, GL_INVALID_ENUM,
1347 "glGetProgramRegisterfvMESA(target)");
1348 return;
1349 }
Brian Paul6d460af2004-04-23 14:16:46 +00001350 if (!ctx->FragmentProgram._Enabled) {
Michal Krol2861e732004-03-29 11:09:34 +00001351 _mesa_error(ctx, GL_INVALID_OPERATION,
1352 "glGetProgramRegisterfvMESA");
1353 return;
1354 }
1355 if (reg[0] == 'R') {
1356 /* Temp register */
1357 GLint i = _mesa_atoi(reg + 1);
1358 if (i >= (GLint)ctx->Const.MaxFragmentProgramTemps) {
1359 _mesa_error(ctx, GL_INVALID_VALUE,
1360 "glGetProgramRegisterfvMESA(registerName)");
1361 return;
1362 }
1363 COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
1364 }
1365 else if (reg[0] == 'f' && reg[1] == '[') {
1366 /* Fragment input attribute */
1367 GLuint i;
1368 for (i = 0; i < ctx->Const.MaxFragmentProgramAttribs; i++) {
1369 const char *name = _mesa_nv_fragment_input_register_name(i);
1370 if (_mesa_strncmp(reg + 2, name, 4) == 0) {
1371 COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
1372 return;
1373 }
1374 }
1375 _mesa_error(ctx, GL_INVALID_VALUE,
1376 "glGetProgramRegisterfvMESA(registerName)");
1377 return;
1378 }
1379 else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
1380 /* Fragment output color */
1381 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLR]);
1382 }
1383 else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
1384 /* Fragment output color */
1385 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLH]);
1386 }
1387 else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
1388 /* Fragment output depth */
1389 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_DEPR]);
1390 }
1391 else {
1392 /* try user-defined identifiers */
1393 const GLfloat *value = _mesa_lookup_parameter_value(
1394 ctx->FragmentProgram.Current->Parameters, -1, reg);
1395 if (value) {
1396 COPY_4V(v, value);
1397 }
1398 else {
1399 _mesa_error(ctx, GL_INVALID_VALUE,
1400 "glGetProgramRegisterfvMESA(registerName)");
1401 return;
1402 }
1403 }
1404 break;
1405 default:
1406 _mesa_error(ctx, GL_INVALID_ENUM,
1407 "glGetProgramRegisterfvMESA(target)");
1408 return;
1409 }
1410
1411}