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