mesa: Use get_local_param_pointer in glProgramLocalParameters4fvEXT().
[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 if (!prog->LocalParams) {
269 prog->LocalParams = calloc(maxParams, sizeof(float[4]));
270 if (!prog->LocalParams)
271 return GL_FALSE;
272 }
273
274 *param = prog->LocalParams[index];
275 return GL_TRUE;
276 }
277
278
279 static GLboolean
280 get_env_param_pointer(struct gl_context *ctx, const char *func,
281 GLenum target, GLuint index, GLfloat **param)
282 {
283 if (target == GL_FRAGMENT_PROGRAM_ARB
284 && ctx->Extensions.ARB_fragment_program) {
285 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
286 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
287 return GL_FALSE;
288 }
289 *param = ctx->FragmentProgram.Parameters[index];
290 return GL_TRUE;
291 }
292 else if (target == GL_VERTEX_PROGRAM_ARB &&
293 ctx->Extensions.ARB_vertex_program) {
294 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
295 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
296 return GL_FALSE;
297 }
298 *param = ctx->VertexProgram.Parameters[index];
299 return GL_TRUE;
300 } else {
301 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
302 return GL_FALSE;
303 }
304 }
305
306 void GLAPIENTRY
307 _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
308 const GLvoid *string)
309 {
310 struct gl_program *base;
311 GET_CURRENT_CONTEXT(ctx);
312
313 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
314
315 if (!ctx->Extensions.ARB_vertex_program
316 && !ctx->Extensions.ARB_fragment_program) {
317 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()");
318 return;
319 }
320
321 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
322 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
323 return;
324 }
325
326 if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) {
327 struct gl_vertex_program *prog = ctx->VertexProgram.Current;
328 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
329
330 base = & prog->Base;
331 }
332 else if (target == GL_FRAGMENT_PROGRAM_ARB
333 && ctx->Extensions.ARB_fragment_program) {
334 struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
335 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
336
337 base = & prog->Base;
338 }
339 else {
340 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
341 return;
342 }
343
344 if (ctx->Program.ErrorPos == -1) {
345 /* finally, give the program to the driver for translation/checking */
346 if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) {
347 _mesa_error(ctx, GL_INVALID_OPERATION,
348 "glProgramStringARB(rejected by driver");
349 }
350 }
351 }
352
353
354 /**
355 * Set a program env parameter register.
356 * \note Called from the GL API dispatcher.
357 */
358 void GLAPIENTRY
359 _mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
360 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
361 {
362 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
363 (GLfloat) z, (GLfloat) w);
364 }
365
366
367 /**
368 * Set a program env parameter register.
369 * \note Called from the GL API dispatcher.
370 */
371 void GLAPIENTRY
372 _mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
373 const GLdouble *params)
374 {
375 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
376 (GLfloat) params[1], (GLfloat) params[2],
377 (GLfloat) params[3]);
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_ProgramEnvParameter4fARB(GLenum target, GLuint index,
387 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
388 {
389 GLfloat *param;
390
391 GET_CURRENT_CONTEXT(ctx);
392
393 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
394
395 if (get_env_param_pointer(ctx, "glProgramEnvParameter",
396 target, index, &param)) {
397 ASSIGN_4V(param, x, y, z, w);
398 }
399 }
400
401
402
403 /**
404 * Set a program env parameter register.
405 * \note Called from the GL API dispatcher.
406 */
407 void GLAPIENTRY
408 _mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
409 const GLfloat *params)
410 {
411 GLfloat *param;
412
413 GET_CURRENT_CONTEXT(ctx);
414
415 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
416
417 if (get_env_param_pointer(ctx, "glProgramEnvParameter4fv",
418 target, index, &param)) {
419 memcpy(param, params, 4 * sizeof(GLfloat));
420 }
421 }
422
423
424 void GLAPIENTRY
425 _mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
426 const GLfloat *params)
427 {
428 GET_CURRENT_CONTEXT(ctx);
429 GLfloat * dest;
430
431 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
432
433 if (count <= 0) {
434 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
435 }
436
437 if (target == GL_FRAGMENT_PROGRAM_ARB
438 && ctx->Extensions.ARB_fragment_program) {
439 if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) {
440 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
441 return;
442 }
443 dest = ctx->FragmentProgram.Parameters[index];
444 }
445 else if (target == GL_VERTEX_PROGRAM_ARB
446 && ctx->Extensions.ARB_vertex_program) {
447 if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) {
448 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
449 return;
450 }
451 dest = ctx->VertexProgram.Parameters[index];
452 }
453 else {
454 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
455 return;
456 }
457
458 memcpy(dest, params, count * 4 * sizeof(GLfloat));
459 }
460
461
462 void GLAPIENTRY
463 _mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
464 GLdouble *params)
465 {
466 GET_CURRENT_CONTEXT(ctx);
467 GLfloat *fparam;
468
469 if (get_env_param_pointer(ctx, "glGetProgramEnvParameterdv",
470 target, index, &fparam)) {
471 COPY_4V(params, fparam);
472 }
473 }
474
475
476 void GLAPIENTRY
477 _mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
478 GLfloat *params)
479 {
480 GLfloat *param;
481
482 GET_CURRENT_CONTEXT(ctx);
483
484 if (get_env_param_pointer(ctx, "glGetProgramEnvParameterfv",
485 target, index, &param)) {
486 COPY_4V(params, param);
487 }
488 }
489
490
491 void GLAPIENTRY
492 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
493 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
494 {
495 GET_CURRENT_CONTEXT(ctx);
496 GLfloat *param;
497
498 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
499
500 if (get_local_param_pointer(ctx, "glProgramLocalParameterARB",
501 target, index, &param)) {
502 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
503 ASSIGN_4V(param, x, y, z, w);
504 }
505 }
506
507
508 void GLAPIENTRY
509 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
510 const GLfloat *params)
511 {
512 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
513 params[2], params[3]);
514 }
515
516
517 void GLAPIENTRY
518 _mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
519 const GLfloat *params)
520 {
521 GET_CURRENT_CONTEXT(ctx);
522 GLfloat *dest;
523
524 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
525
526 if (count <= 0) {
527 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
528 }
529
530 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
531 target, index, &dest)) {
532 GLuint maxParams = target == GL_FRAGMENT_PROGRAM_ARB ?
533 ctx->Const.FragmentProgram.MaxLocalParams :
534 ctx->Const.VertexProgram.MaxLocalParams;
535
536 if ((index + count) > maxParams) {
537 _mesa_error(ctx, GL_INVALID_VALUE,
538 "glProgramLocalParameters4fvEXT(index + count)");
539 return;
540 }
541
542 memcpy(dest, params, count * 4 * sizeof(GLfloat));
543 }
544 }
545
546
547 void GLAPIENTRY
548 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
549 GLdouble x, GLdouble y,
550 GLdouble z, GLdouble w)
551 {
552 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
553 (GLfloat) z, (GLfloat) w);
554 }
555
556
557 void GLAPIENTRY
558 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
559 const GLdouble *params)
560 {
561 _mesa_ProgramLocalParameter4fARB(target, index,
562 (GLfloat) params[0], (GLfloat) params[1],
563 (GLfloat) params[2], (GLfloat) params[3]);
564 }
565
566
567 void GLAPIENTRY
568 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
569 GLfloat *params)
570 {
571 GLfloat *param;
572 GET_CURRENT_CONTEXT(ctx);
573
574 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
575 target, index, &param)) {
576 COPY_4V(params, param);
577 }
578 }
579
580
581 void GLAPIENTRY
582 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
583 GLdouble *params)
584 {
585 GLfloat *param;
586 GET_CURRENT_CONTEXT(ctx);
587
588 if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
589 target, index, &param)) {
590 COPY_4V(params, param);
591 }
592 }
593
594
595 void GLAPIENTRY
596 _mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
597 {
598 const struct gl_program_constants *limits;
599 struct gl_program *prog;
600 GET_CURRENT_CONTEXT(ctx);
601
602 if (target == GL_VERTEX_PROGRAM_ARB
603 && ctx->Extensions.ARB_vertex_program) {
604 prog = &(ctx->VertexProgram.Current->Base);
605 limits = &ctx->Const.VertexProgram;
606 }
607 else if (target == GL_FRAGMENT_PROGRAM_ARB
608 && ctx->Extensions.ARB_fragment_program) {
609 prog = &(ctx->FragmentProgram.Current->Base);
610 limits = &ctx->Const.FragmentProgram;
611 }
612 else {
613 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
614 return;
615 }
616
617 ASSERT(prog);
618 ASSERT(limits);
619
620 /* Queries supported for both vertex and fragment programs */
621 switch (pname) {
622 case GL_PROGRAM_LENGTH_ARB:
623 *params
624 = prog->String ? (GLint) strlen((char *) prog->String) : 0;
625 return;
626 case GL_PROGRAM_FORMAT_ARB:
627 *params = prog->Format;
628 return;
629 case GL_PROGRAM_BINDING_ARB:
630 *params = prog->Id;
631 return;
632 case GL_PROGRAM_INSTRUCTIONS_ARB:
633 *params = prog->NumInstructions;
634 return;
635 case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
636 *params = limits->MaxInstructions;
637 return;
638 case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
639 *params = prog->NumNativeInstructions;
640 return;
641 case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
642 *params = limits->MaxNativeInstructions;
643 return;
644 case GL_PROGRAM_TEMPORARIES_ARB:
645 *params = prog->NumTemporaries;
646 return;
647 case GL_MAX_PROGRAM_TEMPORARIES_ARB:
648 *params = limits->MaxTemps;
649 return;
650 case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
651 *params = prog->NumNativeTemporaries;
652 return;
653 case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
654 *params = limits->MaxNativeTemps;
655 return;
656 case GL_PROGRAM_PARAMETERS_ARB:
657 *params = prog->NumParameters;
658 return;
659 case GL_MAX_PROGRAM_PARAMETERS_ARB:
660 *params = limits->MaxParameters;
661 return;
662 case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
663 *params = prog->NumNativeParameters;
664 return;
665 case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
666 *params = limits->MaxNativeParameters;
667 return;
668 case GL_PROGRAM_ATTRIBS_ARB:
669 *params = prog->NumAttributes;
670 return;
671 case GL_MAX_PROGRAM_ATTRIBS_ARB:
672 *params = limits->MaxAttribs;
673 return;
674 case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
675 *params = prog->NumNativeAttributes;
676 return;
677 case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
678 *params = limits->MaxNativeAttribs;
679 return;
680 case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
681 *params = prog->NumAddressRegs;
682 return;
683 case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
684 *params = limits->MaxAddressRegs;
685 return;
686 case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
687 *params = prog->NumNativeAddressRegs;
688 return;
689 case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
690 *params = limits->MaxNativeAddressRegs;
691 return;
692 case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
693 *params = limits->MaxLocalParams;
694 return;
695 case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
696 *params = limits->MaxEnvParams;
697 return;
698 case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
699 /*
700 * XXX we may not really need a driver callback here.
701 * If the number of native instructions, registers, etc. used
702 * are all below the maximums, we could return true.
703 * The spec says that even if this query returns true, there's
704 * no guarantee that the program will run in hardware.
705 */
706 if (prog->Id == 0) {
707 /* default/null program */
708 *params = GL_FALSE;
709 }
710 else if (ctx->Driver.IsProgramNative) {
711 /* ask the driver */
712 *params = ctx->Driver.IsProgramNative( ctx, target, prog );
713 }
714 else {
715 /* probably running in software */
716 *params = GL_TRUE;
717 }
718 return;
719 default:
720 /* continue with fragment-program only queries below */
721 break;
722 }
723
724 /*
725 * The following apply to fragment programs only (at this time)
726 */
727 if (target == GL_FRAGMENT_PROGRAM_ARB) {
728 const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
729 switch (pname) {
730 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
731 *params = fp->Base.NumNativeAluInstructions;
732 return;
733 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
734 *params = fp->Base.NumAluInstructions;
735 return;
736 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
737 *params = fp->Base.NumTexInstructions;
738 return;
739 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
740 *params = fp->Base.NumNativeTexInstructions;
741 return;
742 case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
743 *params = fp->Base.NumTexIndirections;
744 return;
745 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
746 *params = fp->Base.NumNativeTexIndirections;
747 return;
748 case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
749 *params = limits->MaxAluInstructions;
750 return;
751 case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
752 *params = limits->MaxNativeAluInstructions;
753 return;
754 case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
755 *params = limits->MaxTexInstructions;
756 return;
757 case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
758 *params = limits->MaxNativeTexInstructions;
759 return;
760 case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
761 *params = limits->MaxTexIndirections;
762 return;
763 case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
764 *params = limits->MaxNativeTexIndirections;
765 return;
766 default:
767 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
768 return;
769 }
770 } else {
771 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
772 return;
773 }
774 }
775
776
777 void GLAPIENTRY
778 _mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
779 {
780 const struct gl_program *prog;
781 char *dst = (char *) string;
782 GET_CURRENT_CONTEXT(ctx);
783
784 if (target == GL_VERTEX_PROGRAM_ARB) {
785 prog = &(ctx->VertexProgram.Current->Base);
786 }
787 else if (target == GL_FRAGMENT_PROGRAM_ARB) {
788 prog = &(ctx->FragmentProgram.Current->Base);
789 }
790 else {
791 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)");
792 return;
793 }
794
795 ASSERT(prog);
796
797 if (pname != GL_PROGRAM_STRING_ARB) {
798 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
799 return;
800 }
801
802 if (prog->String)
803 memcpy(dst, prog->String, strlen((char *) prog->String));
804 else
805 *dst = '\0';
806 }