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