mesa: make use of ralloc when creating ARB asm gl_program fields
[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 = rzalloc_array_size(prog, sizeof(float[4]),
279 maxParams);
280
281 if (!prog->LocalParams)
282 return GL_FALSE;
283 }
284
285 *param = prog->LocalParams[index];
286 return GL_TRUE;
287 }
288
289
290 static GLboolean
291 get_env_param_pointer(struct gl_context *ctx, const char *func,
292 GLenum target, GLuint index, GLfloat **param)
293 {
294 if (target == GL_FRAGMENT_PROGRAM_ARB
295 && ctx->Extensions.ARB_fragment_program) {
296 if (index >= ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxEnvParams) {
297 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
298 return GL_FALSE;
299 }
300 *param = ctx->FragmentProgram.Parameters[index];
301 return GL_TRUE;
302 }
303 else if (target == GL_VERTEX_PROGRAM_ARB &&
304 ctx->Extensions.ARB_vertex_program) {
305 if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxEnvParams) {
306 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
307 return GL_FALSE;
308 }
309 *param = ctx->VertexProgram.Parameters[index];
310 return GL_TRUE;
311 } else {
312 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
313 return GL_FALSE;
314 }
315 }
316
317 void GLAPIENTRY
318 _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
319 const GLvoid *string)
320 {
321 struct gl_program *prog;
322 bool failed;
323 GET_CURRENT_CONTEXT(ctx);
324
325 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
326
327 if (!ctx->Extensions.ARB_vertex_program
328 && !ctx->Extensions.ARB_fragment_program) {
329 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()");
330 return;
331 }
332
333 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
334 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
335 return;
336 }
337
338 if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) {
339 prog = ctx->VertexProgram.Current;
340 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
341 }
342 else if (target == GL_FRAGMENT_PROGRAM_ARB
343 && ctx->Extensions.ARB_fragment_program) {
344 prog = ctx->FragmentProgram.Current;
345 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
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, prog)) {
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, prog->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, prog->Id);
374 } else {
375 fprintf(stderr, "Mesa IR for ARB_%s_program %d:\n",
376 shader_type, prog->Id);
377 _mesa_print_program(prog);
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], prog->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;
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;
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_program *fp = ctx->FragmentProgram.Current;
781 switch (pname) {
782 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
783 *params = fp->NumNativeAluInstructions;
784 return;
785 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
786 *params = fp->NumAluInstructions;
787 return;
788 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
789 *params = fp->NumTexInstructions;
790 return;
791 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
792 *params = fp->NumNativeTexInstructions;
793 return;
794 case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
795 *params = fp->NumTexIndirections;
796 return;
797 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
798 *params = fp->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;
838 }
839 else if (target == GL_FRAGMENT_PROGRAM_ARB) {
840 prog = ctx->FragmentProgram.Current;
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 }