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