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