Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / shader / arbprogram.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.0
4 *
5 * Copyright (C) 1999-2007 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 arbprogram.c
27 * ARB_vertex/fragment_program state management functions.
28 * \author Brian Paul
29 */
30
31
32 #include "main/glheader.h"
33 #include "main/context.h"
34 #include "main/hash.h"
35 #include "main/imports.h"
36 #include "main/macros.h"
37 #include "main/mtypes.h"
38 #include "arbprogram.h"
39 #include "arbprogparse.h"
40 #include "program.h"
41
42
43
44 /**
45 * Mixing ARB and NV vertex/fragment programs can be tricky.
46 * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
47 * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
48 * The two different fragment program targets are supposed to be compatible
49 * to some extent (see GL_ARB_fragment_program spec).
50 * This function does the compatibility check.
51 */
52 static GLboolean
53 compatible_program_targets(GLenum t1, GLenum t2)
54 {
55 if (t1 == t2)
56 return GL_TRUE;
57 if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
58 return GL_TRUE;
59 if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
60 return GL_TRUE;
61 return GL_FALSE;
62 }
63
64
65 /**
66 * Bind a program (make it current)
67 * \note Called from the GL API dispatcher by both glBindProgramNV
68 * and glBindProgramARB.
69 */
70 void GLAPIENTRY
71 _mesa_BindProgram(GLenum target, GLuint id)
72 {
73 struct gl_program *curProg, *newProg;
74 GET_CURRENT_CONTEXT(ctx);
75 ASSERT_OUTSIDE_BEGIN_END(ctx);
76
77 /* Error-check target and get curProg */
78 if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
79 (ctx->Extensions.NV_vertex_program ||
80 ctx->Extensions.ARB_vertex_program)) {
81 curProg = &ctx->VertexProgram.Current->Base;
82 }
83 else if ((target == GL_FRAGMENT_PROGRAM_NV
84 && ctx->Extensions.NV_fragment_program) ||
85 (target == GL_FRAGMENT_PROGRAM_ARB
86 && ctx->Extensions.ARB_fragment_program)) {
87 curProg = &ctx->FragmentProgram.Current->Base;
88 }
89 else {
90 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
91 return;
92 }
93
94 /*
95 * Get pointer to new program to bind.
96 * NOTE: binding to a non-existant program is not an error.
97 * That's supposed to be caught in glBegin.
98 */
99 if (id == 0) {
100 /* Bind a default program */
101 newProg = NULL;
102 if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
103 newProg = &ctx->Shared->DefaultVertexProgram->Base;
104 else
105 newProg = &ctx->Shared->DefaultFragmentProgram->Base;
106 }
107 else {
108 /* Bind a user program */
109 newProg = _mesa_lookup_program(ctx, id);
110 if (!newProg || newProg == &_mesa_DummyProgram) {
111 /* allocate a new program now */
112 newProg = ctx->Driver.NewProgram(ctx, target, id);
113 if (!newProg) {
114 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
115 return;
116 }
117 _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
118 }
119 else if (!compatible_program_targets(newProg->Target, target)) {
120 _mesa_error(ctx, GL_INVALID_OPERATION,
121 "glBindProgramNV/ARB(target mismatch)");
122 return;
123 }
124 }
125
126 /** All error checking is complete now **/
127
128 if (curProg->Id == id) {
129 /* binding same program - no change */
130 return;
131 }
132
133 /* signal new program (and its new constants) */
134 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
135
136 /* bind newProg */
137 if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
138 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
139 (struct gl_vertex_program *) newProg);
140 }
141 else if (target == GL_FRAGMENT_PROGRAM_NV ||
142 target == GL_FRAGMENT_PROGRAM_ARB) {
143 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
144 (struct gl_fragment_program *) newProg);
145 }
146
147 /* Never null pointers */
148 ASSERT(ctx->VertexProgram.Current);
149 ASSERT(ctx->FragmentProgram.Current);
150
151 if (ctx->Driver.BindProgram)
152 ctx->Driver.BindProgram(ctx, target, newProg);
153 }
154
155
156 /**
157 * Delete a list of programs.
158 * \note Not compiled into display lists.
159 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
160 */
161 void GLAPIENTRY
162 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
163 {
164 GLint i;
165 GET_CURRENT_CONTEXT(ctx);
166 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
167
168 if (n < 0) {
169 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
170 return;
171 }
172
173 for (i = 0; i < n; i++) {
174 if (ids[i] != 0) {
175 struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
176 if (prog == &_mesa_DummyProgram) {
177 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
178 }
179 else if (prog) {
180 /* Unbind program if necessary */
181 if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */
182 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
183 if (ctx->VertexProgram.Current &&
184 ctx->VertexProgram.Current->Base.Id == ids[i]) {
185 /* unbind this currently bound program */
186 _mesa_BindProgram(prog->Target, 0);
187 }
188 }
189 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
190 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
191 if (ctx->FragmentProgram.Current &&
192 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
193 /* unbind this currently bound program */
194 _mesa_BindProgram(prog->Target, 0);
195 }
196 }
197 else {
198 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
199 return;
200 }
201 /* The ID is immediately available for re-use now */
202 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
203 _mesa_reference_program(ctx, &prog, NULL);
204 }
205 }
206 }
207 }
208
209
210 /**
211 * Generate a list of new program identifiers.
212 * \note Not compiled into display lists.
213 * \note Called by both glGenProgramsNV and glGenProgramsARB.
214 */
215 void GLAPIENTRY
216 _mesa_GenPrograms(GLsizei n, GLuint *ids)
217 {
218 GLuint first;
219 GLuint i;
220 GET_CURRENT_CONTEXT(ctx);
221 ASSERT_OUTSIDE_BEGIN_END(ctx);
222
223 if (n < 0) {
224 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
225 return;
226 }
227
228 if (!ids)
229 return;
230
231 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
232
233 /* Insert pointer to dummy program as placeholder */
234 for (i = 0; i < (GLuint) n; i++) {
235 _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
236 }
237
238 /* Return the program names */
239 for (i = 0; i < (GLuint) n; i++) {
240 ids[i] = first + i;
241 }
242 }
243
244
245 void GLAPIENTRY
246 _mesa_EnableVertexAttribArrayARB(GLuint index)
247 {
248 GET_CURRENT_CONTEXT(ctx);
249 ASSERT_OUTSIDE_BEGIN_END(ctx);
250
251 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
252 _mesa_error(ctx, GL_INVALID_VALUE,
253 "glEnableVertexAttribArrayARB(index)");
254 return;
255 }
256
257 FLUSH_VERTICES(ctx, _NEW_ARRAY);
258 ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_TRUE;
259 ctx->Array.ArrayObj->_Enabled |= _NEW_ARRAY_ATTRIB(index);
260 ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
261 }
262
263
264 void GLAPIENTRY
265 _mesa_DisableVertexAttribArrayARB(GLuint index)
266 {
267 GET_CURRENT_CONTEXT(ctx);
268 ASSERT_OUTSIDE_BEGIN_END(ctx);
269
270 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
271 _mesa_error(ctx, GL_INVALID_VALUE,
272 "glEnableVertexAttribArrayARB(index)");
273 return;
274 }
275
276 FLUSH_VERTICES(ctx, _NEW_ARRAY);
277 ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_FALSE;
278 ctx->Array.ArrayObj->_Enabled &= ~_NEW_ARRAY_ATTRIB(index);
279 ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
280 }
281
282
283 void GLAPIENTRY
284 _mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params)
285 {
286 GLfloat fparams[4];
287 GET_CURRENT_CONTEXT(ctx);
288 ASSERT_OUTSIDE_BEGIN_END(ctx);
289
290 _mesa_GetVertexAttribfvARB(index, pname, fparams);
291 if (ctx->ErrorValue == GL_NO_ERROR) {
292 if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
293 COPY_4V(params, fparams);
294 }
295 else {
296 params[0] = fparams[0];
297 }
298 }
299 }
300
301
302 void GLAPIENTRY
303 _mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params)
304 {
305 GET_CURRENT_CONTEXT(ctx);
306 ASSERT_OUTSIDE_BEGIN_END(ctx);
307
308 if (index >= MAX_VERTEX_PROGRAM_ATTRIBS) {
309 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribfvARB(index)");
310 return;
311 }
312
313 switch (pname) {
314 case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
315 params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Enabled;
316 break;
317 case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
318 params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Size;
319 break;
320 case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
321 params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Stride;
322 break;
323 case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
324 params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].Type;
325 break;
326 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
327 params[0] = ctx->Array.ArrayObj->VertexAttrib[index].Normalized;
328 break;
329 case GL_CURRENT_VERTEX_ATTRIB_ARB:
330 if (index == 0) {
331 _mesa_error(ctx, GL_INVALID_OPERATION,
332 "glGetVertexAttribfvARB(index==0)");
333 return;
334 }
335 FLUSH_CURRENT(ctx, 0);
336 COPY_4V(params, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + index]);
337 break;
338 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
339 params[0] = (GLfloat) ctx->Array.ArrayObj->VertexAttrib[index].BufferObj->Name;
340 break;
341 default:
342 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)");
343 return;
344 }
345 }
346
347
348 void GLAPIENTRY
349 _mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params)
350 {
351 GLfloat fparams[4];
352 GET_CURRENT_CONTEXT(ctx);
353 ASSERT_OUTSIDE_BEGIN_END(ctx);
354
355 _mesa_GetVertexAttribfvARB(index, pname, fparams);
356 if (ctx->ErrorValue == GL_NO_ERROR) {
357 if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
358 COPY_4V_CAST(params, fparams, GLint); /* float to int */
359 }
360 else {
361 params[0] = (GLint) fparams[0];
362 }
363 }
364 }
365
366
367 void GLAPIENTRY
368 _mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer)
369 {
370 GET_CURRENT_CONTEXT(ctx);
371 ASSERT_OUTSIDE_BEGIN_END(ctx);
372
373 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
374 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)");
375 return;
376 }
377
378 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) {
379 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)");
380 return;
381 }
382
383 *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
384 }
385
386
387 /**
388 * Determine if id names a vertex or fragment program.
389 * \note Not compiled into display lists.
390 * \note Called from both glIsProgramNV and glIsProgramARB.
391 * \param id is the program identifier
392 * \return GL_TRUE if id is a program, else GL_FALSE.
393 */
394 GLboolean GLAPIENTRY
395 _mesa_IsProgramARB(GLuint id)
396 {
397 struct gl_program *prog = NULL;
398 GET_CURRENT_CONTEXT(ctx);
399 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
400
401 if (id == 0)
402 return GL_FALSE;
403
404 prog = _mesa_lookup_program(ctx, id);
405 if (prog && (prog != &_mesa_DummyProgram))
406 return GL_TRUE;
407 else
408 return GL_FALSE;
409 }
410
411
412 void GLAPIENTRY
413 _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
414 const GLvoid *string)
415 {
416 GET_CURRENT_CONTEXT(ctx);
417 ASSERT_OUTSIDE_BEGIN_END(ctx);
418
419 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
420
421 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
422 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
423 return;
424 }
425
426 if (target == GL_VERTEX_PROGRAM_ARB
427 && ctx->Extensions.ARB_vertex_program) {
428 struct gl_vertex_program *prog = ctx->VertexProgram.Current;
429 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
430
431 if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify)
432 ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base );
433 }
434 else if (target == GL_FRAGMENT_PROGRAM_ARB
435 && ctx->Extensions.ARB_fragment_program) {
436 struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
437 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
438
439 if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify)
440 ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base );
441 }
442 else {
443 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
444 return;
445 }
446 }
447
448
449 /**
450 * Set a program env parameter register.
451 * \note Called from the GL API dispatcher.
452 * Note, this function is also used by the GL_NV_vertex_program extension
453 * (alias to ProgramParameterdNV)
454 */
455 void GLAPIENTRY
456 _mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
457 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
458 {
459 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
460 (GLfloat) z, (GLfloat) w);
461 }
462
463
464 /**
465 * Set a program env parameter register.
466 * \note Called from the GL API dispatcher.
467 * Note, this function is also used by the GL_NV_vertex_program extension
468 * (alias to ProgramParameterdvNV)
469 */
470 void GLAPIENTRY
471 _mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
472 const GLdouble *params)
473 {
474 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
475 (GLfloat) params[1], (GLfloat) params[2],
476 (GLfloat) params[3]);
477 }
478
479
480 /**
481 * Set a program env parameter register.
482 * \note Called from the GL API dispatcher.
483 * Note, this function is also used by the GL_NV_vertex_program extension
484 * (alias to ProgramParameterfNV)
485 */
486 void GLAPIENTRY
487 _mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
488 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
489 {
490 GET_CURRENT_CONTEXT(ctx);
491 ASSERT_OUTSIDE_BEGIN_END(ctx);
492
493 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
494
495 if (target == GL_FRAGMENT_PROGRAM_ARB
496 && ctx->Extensions.ARB_fragment_program) {
497 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
498 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
499 return;
500 }
501 ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w);
502 }
503 else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */
504 && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) {
505 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
506 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
507 return;
508 }
509 ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w);
510 }
511 else {
512 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)");
513 return;
514 }
515 }
516
517 /**
518 * Set a program env parameter register.
519 * \note Called from the GL API dispatcher.
520 * Note, this function is also used by the GL_NV_vertex_program extension
521 * (alias to ProgramParameterfvNV)
522 */
523 void GLAPIENTRY
524 _mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
525 const GLfloat *params)
526 {
527 _mesa_ProgramEnvParameter4fARB(target, index, params[0], params[1],
528 params[2], params[3]);
529 }
530
531
532 void GLAPIENTRY
533 _mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
534 const GLfloat *params)
535 {
536 GET_CURRENT_CONTEXT(ctx);
537 GLint i;
538 GLfloat * dest;
539 ASSERT_OUTSIDE_BEGIN_END(ctx);
540
541 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
542
543 if (count <= 0) {
544 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
545 }
546
547 if (target == GL_FRAGMENT_PROGRAM_ARB
548 && ctx->Extensions.ARB_fragment_program) {
549 if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) {
550 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
551 return;
552 }
553 dest = ctx->FragmentProgram.Parameters[index];
554 }
555 else if (target == GL_VERTEX_PROGRAM_ARB
556 && ctx->Extensions.ARB_vertex_program) {
557 if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) {
558 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
559 return;
560 }
561 dest = ctx->VertexProgram.Parameters[index];
562 }
563 else {
564 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
565 return;
566 }
567
568 for ( i = 0 ; i < count ; i++ ) {
569 COPY_4V(dest, params);
570 params += 4;
571 dest += 4;
572 }
573 }
574
575
576 void GLAPIENTRY
577 _mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
578 GLdouble *params)
579 {
580 GET_CURRENT_CONTEXT(ctx);
581 GLfloat fparams[4];
582
583 _mesa_GetProgramEnvParameterfvARB(target, index, fparams);
584 if (ctx->ErrorValue == GL_NO_ERROR) {
585 params[0] = fparams[0];
586 params[1] = fparams[1];
587 params[2] = fparams[2];
588 params[3] = fparams[3];
589 }
590 }
591
592
593 void GLAPIENTRY
594 _mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
595 GLfloat *params)
596 {
597 GET_CURRENT_CONTEXT(ctx);
598
599 ASSERT_OUTSIDE_BEGIN_END(ctx);
600
601 if (target == GL_FRAGMENT_PROGRAM_ARB
602 && ctx->Extensions.ARB_fragment_program) {
603 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
604 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
605 return;
606 }
607 COPY_4V(params, ctx->FragmentProgram.Parameters[index]);
608 }
609 else if (target == GL_VERTEX_PROGRAM_ARB
610 && ctx->Extensions.ARB_vertex_program) {
611 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
612 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
613 return;
614 }
615 COPY_4V(params, ctx->VertexProgram.Parameters[index]);
616 }
617 else {
618 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)");
619 return;
620 }
621 }
622
623
624 /**
625 * Note, this function is also used by the GL_NV_fragment_program extension.
626 */
627 void GLAPIENTRY
628 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
629 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
630 {
631 GET_CURRENT_CONTEXT(ctx);
632 struct gl_program *prog;
633 ASSERT_OUTSIDE_BEGIN_END(ctx);
634
635 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
636
637 if ((target == GL_FRAGMENT_PROGRAM_NV
638 && ctx->Extensions.NV_fragment_program) ||
639 (target == GL_FRAGMENT_PROGRAM_ARB
640 && ctx->Extensions.ARB_fragment_program)) {
641 if (index >= ctx->Const.FragmentProgram.MaxLocalParams) {
642 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
643 return;
644 }
645 prog = &(ctx->FragmentProgram.Current->Base);
646 }
647 else if (target == GL_VERTEX_PROGRAM_ARB
648 && ctx->Extensions.ARB_vertex_program) {
649 if (index >= ctx->Const.VertexProgram.MaxLocalParams) {
650 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
651 return;
652 }
653 prog = &(ctx->VertexProgram.Current->Base);
654 }
655 else {
656 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
657 return;
658 }
659
660 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
661 prog->LocalParams[index][0] = x;
662 prog->LocalParams[index][1] = y;
663 prog->LocalParams[index][2] = z;
664 prog->LocalParams[index][3] = w;
665 }
666
667
668 /**
669 * Note, this function is also used by the GL_NV_fragment_program extension.
670 */
671 void GLAPIENTRY
672 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
673 const GLfloat *params)
674 {
675 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
676 params[2], params[3]);
677 }
678
679
680 void GLAPIENTRY
681 _mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
682 const GLfloat *params)
683 {
684 GET_CURRENT_CONTEXT(ctx);
685 struct gl_program *prog;
686 GLint i;
687 ASSERT_OUTSIDE_BEGIN_END(ctx);
688
689 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
690
691 if (count <= 0) {
692 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
693 }
694
695 if (target == GL_FRAGMENT_PROGRAM_ARB
696 && ctx->Extensions.ARB_fragment_program) {
697 if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) {
698 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
699 return;
700 }
701 prog = &(ctx->FragmentProgram.Current->Base);
702 }
703 else if (target == GL_VERTEX_PROGRAM_ARB
704 && ctx->Extensions.ARB_vertex_program) {
705 if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) {
706 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
707 return;
708 }
709 prog = &(ctx->VertexProgram.Current->Base);
710 }
711 else {
712 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)");
713 return;
714 }
715
716 for (i = 0; i < count; i++) {
717 ASSERT((index + i) < MAX_PROGRAM_LOCAL_PARAMS);
718 COPY_4V(prog->LocalParams[index + i], params);
719 params += 4;
720 }
721 }
722
723
724 /**
725 * Note, this function is also used by the GL_NV_fragment_program extension.
726 */
727 void GLAPIENTRY
728 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
729 GLdouble x, GLdouble y,
730 GLdouble z, GLdouble w)
731 {
732 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
733 (GLfloat) z, (GLfloat) w);
734 }
735
736
737 /**
738 * Note, this function is also used by the GL_NV_fragment_program extension.
739 */
740 void GLAPIENTRY
741 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
742 const GLdouble *params)
743 {
744 _mesa_ProgramLocalParameter4fARB(target, index,
745 (GLfloat) params[0], (GLfloat) params[1],
746 (GLfloat) params[2], (GLfloat) params[3]);
747 }
748
749
750 /**
751 * Note, this function is also used by the GL_NV_fragment_program extension.
752 */
753 void GLAPIENTRY
754 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
755 GLfloat *params)
756 {
757 const struct gl_program *prog;
758 GLuint maxParams;
759 GET_CURRENT_CONTEXT(ctx);
760 ASSERT_OUTSIDE_BEGIN_END(ctx);
761
762 if (target == GL_VERTEX_PROGRAM_ARB
763 && ctx->Extensions.ARB_vertex_program) {
764 prog = &(ctx->VertexProgram.Current->Base);
765 maxParams = ctx->Const.VertexProgram.MaxLocalParams;
766 }
767 else if (target == GL_FRAGMENT_PROGRAM_ARB
768 && ctx->Extensions.ARB_fragment_program) {
769 prog = &(ctx->FragmentProgram.Current->Base);
770 maxParams = ctx->Const.FragmentProgram.MaxLocalParams;
771 }
772 else if (target == GL_FRAGMENT_PROGRAM_NV
773 && ctx->Extensions.NV_fragment_program) {
774 prog = &(ctx->FragmentProgram.Current->Base);
775 maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
776 }
777 else {
778 _mesa_error(ctx, GL_INVALID_ENUM,
779 "glGetProgramLocalParameterARB(target)");
780 return;
781 }
782
783 if (index >= maxParams) {
784 _mesa_error(ctx, GL_INVALID_VALUE,
785 "glGetProgramLocalParameterARB(index)");
786 return;
787 }
788
789 ASSERT(prog);
790 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
791 COPY_4V(params, prog->LocalParams[index]);
792 }
793
794
795 /**
796 * Note, this function is also used by the GL_NV_fragment_program extension.
797 */
798 void GLAPIENTRY
799 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
800 GLdouble *params)
801 {
802 GET_CURRENT_CONTEXT(ctx);
803 GLfloat floatParams[4];
804 ASSIGN_4V(floatParams, 0.0F, 0.0F, 0.0F, 0.0F);
805 _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
806 if (ctx->ErrorValue == GL_NO_ERROR) {
807 COPY_4V(params, floatParams);
808 }
809 }
810
811
812 void GLAPIENTRY
813 _mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
814 {
815 const struct gl_program_constants *limits;
816 struct gl_program *prog;
817 GET_CURRENT_CONTEXT(ctx);
818
819 ASSERT_OUTSIDE_BEGIN_END(ctx);
820
821 if (target == GL_VERTEX_PROGRAM_ARB
822 && ctx->Extensions.ARB_vertex_program) {
823 prog = &(ctx->VertexProgram.Current->Base);
824 limits = &ctx->Const.VertexProgram;
825 }
826 else if (target == GL_FRAGMENT_PROGRAM_ARB
827 && ctx->Extensions.ARB_fragment_program) {
828 prog = &(ctx->FragmentProgram.Current->Base);
829 limits = &ctx->Const.FragmentProgram;
830 }
831 else {
832 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
833 return;
834 }
835
836 ASSERT(prog);
837 ASSERT(limits);
838
839 /* Queries supported for both vertex and fragment programs */
840 switch (pname) {
841 case GL_PROGRAM_LENGTH_ARB:
842 *params
843 = prog->String ? (GLint) _mesa_strlen((char *) prog->String) : 0;
844 return;
845 case GL_PROGRAM_FORMAT_ARB:
846 *params = prog->Format;
847 return;
848 case GL_PROGRAM_BINDING_ARB:
849 *params = prog->Id;
850 return;
851 case GL_PROGRAM_INSTRUCTIONS_ARB:
852 *params = prog->NumInstructions;
853 return;
854 case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
855 *params = limits->MaxInstructions;
856 return;
857 case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
858 *params = prog->NumNativeInstructions;
859 return;
860 case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
861 *params = limits->MaxNativeInstructions;
862 return;
863 case GL_PROGRAM_TEMPORARIES_ARB:
864 *params = prog->NumTemporaries;
865 return;
866 case GL_MAX_PROGRAM_TEMPORARIES_ARB:
867 *params = limits->MaxTemps;
868 return;
869 case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
870 *params = prog->NumNativeTemporaries;
871 return;
872 case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
873 *params = limits->MaxNativeTemps;
874 return;
875 case GL_PROGRAM_PARAMETERS_ARB:
876 *params = prog->NumParameters;
877 return;
878 case GL_MAX_PROGRAM_PARAMETERS_ARB:
879 *params = limits->MaxParameters;
880 return;
881 case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
882 *params = prog->NumNativeParameters;
883 return;
884 case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
885 *params = limits->MaxNativeParameters;
886 return;
887 case GL_PROGRAM_ATTRIBS_ARB:
888 *params = prog->NumAttributes;
889 return;
890 case GL_MAX_PROGRAM_ATTRIBS_ARB:
891 *params = limits->MaxAttribs;
892 return;
893 case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
894 *params = prog->NumNativeAttributes;
895 return;
896 case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
897 *params = limits->MaxNativeAttribs;
898 return;
899 case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
900 *params = prog->NumAddressRegs;
901 return;
902 case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
903 *params = limits->MaxAddressRegs;
904 return;
905 case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
906 *params = prog->NumNativeAddressRegs;
907 return;
908 case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
909 *params = limits->MaxNativeAddressRegs;
910 return;
911 case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
912 *params = limits->MaxLocalParams;
913 return;
914 case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
915 *params = limits->MaxEnvParams;
916 return;
917 case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
918 /*
919 * XXX we may not really need a driver callback here.
920 * If the number of native instructions, registers, etc. used
921 * are all below the maximums, we could return true.
922 * The spec says that even if this query returns true, there's
923 * no guarantee that the program will run in hardware.
924 */
925 if (prog->Id == 0) {
926 /* default/null program */
927 *params = GL_FALSE;
928 }
929 else if (ctx->Driver.IsProgramNative) {
930 /* ask the driver */
931 *params = ctx->Driver.IsProgramNative( ctx, target, prog );
932 }
933 else {
934 /* probably running in software */
935 *params = GL_TRUE;
936 }
937 return;
938 default:
939 /* continue with fragment-program only queries below */
940 break;
941 }
942
943 /*
944 * The following apply to fragment programs only (at this time)
945 */
946 if (target == GL_FRAGMENT_PROGRAM_ARB) {
947 const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
948 switch (pname) {
949 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
950 *params = fp->Base.NumNativeAluInstructions;
951 return;
952 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
953 *params = fp->Base.NumAluInstructions;
954 return;
955 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
956 *params = fp->Base.NumTexInstructions;
957 return;
958 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
959 *params = fp->Base.NumNativeTexInstructions;
960 return;
961 case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
962 *params = fp->Base.NumTexIndirections;
963 return;
964 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
965 *params = fp->Base.NumNativeTexIndirections;
966 return;
967 case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
968 *params = limits->MaxAluInstructions;
969 return;
970 case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
971 *params = limits->MaxNativeAluInstructions;
972 return;
973 case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
974 *params = limits->MaxTexInstructions;
975 return;
976 case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
977 *params = limits->MaxNativeTexInstructions;
978 return;
979 case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
980 *params = limits->MaxTexIndirections;
981 return;
982 case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
983 *params = limits->MaxNativeTexIndirections;
984 return;
985 default:
986 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
987 return;
988 }
989 }
990 }
991
992
993 void GLAPIENTRY
994 _mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
995 {
996 const struct gl_program *prog;
997 char *dst = (char *) string;
998 GET_CURRENT_CONTEXT(ctx);
999
1000 ASSERT_OUTSIDE_BEGIN_END(ctx);
1001
1002 if (target == GL_VERTEX_PROGRAM_ARB) {
1003 prog = &(ctx->VertexProgram.Current->Base);
1004 }
1005 else if (target == GL_FRAGMENT_PROGRAM_ARB) {
1006 prog = &(ctx->FragmentProgram.Current->Base);
1007 }
1008 else {
1009 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)");
1010 return;
1011 }
1012
1013 ASSERT(prog);
1014
1015 if (pname != GL_PROGRAM_STRING_ARB) {
1016 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
1017 return;
1018 }
1019
1020 if (prog->String)
1021 _mesa_memcpy(dst, prog->String, _mesa_strlen((char *) prog->String));
1022 else
1023 *dst = '\0';
1024 }