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