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