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