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