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