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