alias ARB/NV program functions where possible
[mesa.git] / src / mesa / main / nvprogram.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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 nvprogram.c
27 * \brief NVIDIA vertex/fragment program state management functions.
28 * \author Brian Paul
29 */
30
31
32 #include "glheader.h"
33 #include "context.h"
34 #include "hash.h"
35 #include "imports.h"
36 #include "macros.h"
37 #include "mtypes.h"
38 #include "nvfragparse.h"
39 #include "nvfragprog.h"
40 #include "nvvertexec.h"
41 #include "nvvertparse.h"
42 #include "nvvertprog.h"
43 #include "nvprogram.h"
44
45
46 /**
47 * Set the vertex/fragment program error state (position and error string).
48 * This is generally called from within the parsers.
49 */
50 void
51 _mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
52 {
53 ctx->Program.ErrorPos = pos;
54 _mesa_free((void *) ctx->Program.ErrorString);
55 if (!string)
56 string = "";
57 ctx->Program.ErrorString = _mesa_strdup(string);
58 }
59
60
61 /**
62 * Find the line number and column for 'pos' within 'string'.
63 * Return a copy of the line which contains 'pos'. Free the line with
64 * _mesa_free().
65 * \param string the program string
66 * \param pos the position within the string
67 * \param line returns the line number corresponding to 'pos'.
68 * \param col returns the column number corresponding to 'pos'.
69 * \return copy of the line containing 'pos'.
70 */
71 const GLubyte *
72 _mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
73 GLint *line, GLint *col)
74 {
75 const GLubyte *lineStart = string;
76 const GLubyte *p = string;
77 GLubyte *s;
78 int len;
79
80 *line = 1;
81
82 while (p != pos) {
83 if (*p == (GLubyte) '\n') {
84 (*line)++;
85 lineStart = p + 1;
86 }
87 p++;
88 }
89
90 *col = (pos - lineStart) + 1;
91
92 /* return copy of this line */
93 while (*p != 0 && *p != '\n')
94 p++;
95 len = p - lineStart;
96 s = (GLubyte *) _mesa_malloc(len + 1);
97 _mesa_memcpy(s, lineStart, len);
98 s[len] = 0;
99
100 return s;
101 }
102
103
104
105 /**
106 * Allocate and initialize a new fragment/vertex program object
107 * \param ctx context
108 * \param id program id/number
109 * \param target program target/type
110 * \return pointer to new program object
111 */
112 struct program *
113 _mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id)
114 {
115 struct program *prog;
116
117 if (target == GL_VERTEX_PROGRAM_NV
118 || target == GL_VERTEX_PROGRAM_ARB) {
119 struct vertex_program *vprog = CALLOC_STRUCT(vertex_program);
120 if (!vprog) {
121 return NULL;
122 }
123 prog = &(vprog->Base);
124 }
125 else if (target == GL_FRAGMENT_PROGRAM_NV
126 || target == GL_FRAGMENT_PROGRAM_ARB) {
127 struct fragment_program *fprog = CALLOC_STRUCT(fragment_program);
128 if (!fprog) {
129 return NULL;
130 }
131 prog = &(fprog->Base);
132 }
133 else {
134 _mesa_problem(ctx, "bad target in _mesa_alloc_program");
135 return NULL;
136 }
137 prog->Id = id;
138 prog->Target = target;
139 prog->Resident = GL_TRUE;
140 prog->RefCount = 1;
141 return prog;
142 }
143
144
145 /**
146 * Delete a program and remove it from the hash table, ignoring the
147 * reference count.
148 * \note Called from the GL API dispatcher.
149 */
150 void
151 _mesa_delete_program(GLcontext *ctx, struct program *prog)
152 {
153 ASSERT(prog);
154
155 if (prog->String)
156 _mesa_free(prog->String);
157 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
158 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
159 struct vertex_program *vprog = (struct vertex_program *) prog;
160 if (vprog->Instructions)
161 _mesa_free(vprog->Instructions);
162 }
163 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
164 struct fragment_program *fprog = (struct fragment_program *) prog;
165 if (fprog->Instructions)
166 _mesa_free(fprog->Instructions);
167 if (fprog->Parameters) {
168 GLuint i;
169 for (i = 0; i < fprog->NumParameters; i++) {
170 _mesa_free((void *) fprog->Parameters[i].Name);
171 }
172 _mesa_free(fprog->Parameters);
173 }
174 }
175 _mesa_free(prog);
176 }
177
178
179 /**
180 * Bind a program (make it current)
181 * \note Called from the GL API dispatcher.
182 */
183 void
184 _mesa_BindProgramNV(GLenum target, GLuint id)
185 {
186 struct program *prog;
187 GET_CURRENT_CONTEXT(ctx);
188 ASSERT_OUTSIDE_BEGIN_END(ctx);
189
190 if (target == GL_VERTEX_PROGRAM_NV
191 && ctx->Extensions.NV_vertex_program) {
192 if (ctx->VertexProgram.Current &&
193 ctx->VertexProgram.Current->Base.Id == id)
194 return;
195 /* decrement refcount on previously bound vertex program */
196 if (ctx->VertexProgram.Current) {
197 ctx->VertexProgram.Current->Base.RefCount--;
198 /* and delete if refcount goes below one */
199 if (ctx->VertexProgram.Current->Base.RefCount <= 0) {
200 _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base));
201 _mesa_HashRemove(ctx->Shared->Programs, id);
202 }
203 }
204 }
205 else if (target == GL_FRAGMENT_PROGRAM_NV
206 && ctx->Extensions.NV_fragment_program) {
207 if (ctx->FragmentProgram.Current &&
208 ctx->FragmentProgram.Current->Base.Id == id)
209 return;
210 /* decrement refcount on previously bound fragment program */
211 if (ctx->FragmentProgram.Current) {
212 ctx->FragmentProgram.Current->Base.RefCount--;
213 /* and delete if refcount goes below one */
214 if (ctx->FragmentProgram.Current->Base.RefCount <= 0) {
215 _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base));
216 _mesa_HashRemove(ctx->Shared->Programs, id);
217 }
218 }
219 }
220 else {
221 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV(target)");
222 return;
223 }
224
225 /* NOTE: binding to a non-existant program is not an error.
226 * That's supposed to be caught in glBegin.
227 */
228 if (id == 0) {
229 /* OK, the null program object */
230 /* XXX use the ARB_vertex/fragment prorgram default objects??? */
231 prog = NULL;
232 }
233 else {
234 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
235 if (prog) {
236 if (prog->Target == 0) {
237 /* prog was allocated with glGenProgramsNV */
238 prog->Target = target;
239 }
240 else if (prog->Target != target) {
241 _mesa_error(ctx, GL_INVALID_OPERATION,
242 "glBindProgramNV(target mismatch)");
243 return;
244 }
245 }
246 else {
247 /* allocate a new program now */
248 prog = _mesa_alloc_program(ctx, target, id);
249 if (!prog) {
250 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV");
251 return;
252 }
253 prog->Id = id;
254 prog->Target = target;
255 prog->Resident = GL_TRUE;
256 prog->RefCount = 1;
257 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
258 }
259 }
260
261 /* bind now */
262 if (target == GL_VERTEX_PROGRAM_NV) {
263 ctx->VertexProgram.Current = (struct vertex_program *) prog;
264 }
265 else if (target == GL_FRAGMENT_PROGRAM_NV) {
266 ctx->FragmentProgram.Current = (struct fragment_program *) prog;
267 }
268
269 if (prog)
270 prog->RefCount++;
271 }
272
273
274 /**
275 * Delete a list of programs.
276 * \note Not compiled into display lists.
277 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
278 */
279 void
280 _mesa_DeleteProgramsNV(GLsizei n, const GLuint *ids)
281 {
282 GLint i;
283 GET_CURRENT_CONTEXT(ctx);
284 ASSERT_OUTSIDE_BEGIN_END(ctx);
285
286 if (n < 0) {
287 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
288 return;
289 }
290
291 for (i = 0; i < n; i++) {
292 if (ids[i] != 0) {
293 struct program *prog = (struct program *)
294 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
295 if (prog) {
296 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
297 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
298 if (ctx->VertexProgram.Current &&
299 ctx->VertexProgram.Current->Base.Id == ids[i]) {
300 /* unbind this currently bound program */
301 _mesa_BindProgramNV(prog->Target, 0);
302 }
303 }
304 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
305 if (ctx->FragmentProgram.Current &&
306 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
307 /* unbind this currently bound program */
308 _mesa_BindProgramNV(prog->Target, 0);
309 }
310 }
311 else {
312 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
313 return;
314 }
315 prog->RefCount--;
316 if (prog->RefCount <= 0) {
317 _mesa_delete_program(ctx, prog);
318 }
319 }
320 }
321 }
322 }
323
324
325 /**
326 * Execute a vertex state program.
327 * \note Called from the GL API dispatcher.
328 */
329 void
330 _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
331 {
332 struct vertex_program *vprog;
333 GET_CURRENT_CONTEXT(ctx);
334 ASSERT_OUTSIDE_BEGIN_END(ctx);
335
336 if (target != GL_VERTEX_STATE_PROGRAM_NV) {
337 _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV");
338 return;
339 }
340
341 vprog = (struct vertex_program *)
342 _mesa_HashLookup(ctx->Shared->Programs, id);
343
344 if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
345 _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
346 return;
347 }
348
349 _mesa_init_vp_registers(ctx);
350 _mesa_init_tracked_matrices(ctx);
351 COPY_4V(ctx->VertexProgram.Machine.Registers[VP_INPUT_REG_START], params);
352 _mesa_exec_vertex_program(ctx, vprog);
353 }
354
355
356 /**
357 * Generate a list of new program identifiers.
358 * \note Not compiled into display lists.
359 * \note Called by both glGenProgramsNV and glGenProgramsARB.
360 */
361 void
362 _mesa_GenProgramsNV(GLsizei n, GLuint *ids)
363 {
364 GLuint first;
365 GLuint i;
366 GET_CURRENT_CONTEXT(ctx);
367 ASSERT_OUTSIDE_BEGIN_END(ctx);
368
369 if (n < 0) {
370 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
371 return;
372 }
373
374 if (!ids)
375 return;
376
377 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
378
379 for (i = 0; i < (GLuint) n; i++) {
380 const int bytes = MAX2(sizeof(struct vertex_program),
381 sizeof(struct fragment_program));
382 struct program *prog = (struct program *) _mesa_calloc(bytes);
383 if (!prog) {
384 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms");
385 return;
386 }
387 prog->RefCount = 1;
388 prog->Id = first + i;
389 _mesa_HashInsert(ctx->Shared->Programs, first + i, prog);
390 }
391
392 /* Return the program names */
393 for (i = 0; i < (GLuint) n; i++) {
394 ids[i] = first + i;
395 }
396 }
397
398
399 /**
400 * Determine if a set of programs is resident in hardware.
401 * \note Not compiled into display lists.
402 * \note Called from the GL API dispatcher.
403 */
404 GLboolean _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
405 GLboolean *residences)
406 {
407 GLint i, j;
408 GLboolean allResident = GL_TRUE;
409 GET_CURRENT_CONTEXT(ctx);
410 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
411
412 if (n < 0) {
413 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
414 return GL_FALSE;
415 }
416
417 for (i = 0; i < n; i++) {
418 const struct program *prog;
419 if (ids[i] == 0) {
420 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
421 return GL_FALSE;
422 }
423 prog = (const struct program *)
424 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
425 if (!prog) {
426 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
427 return GL_FALSE;
428 }
429 if (prog->Resident) {
430 if (!allResident)
431 residences[i] = GL_TRUE;
432 }
433 else {
434 if (allResident) {
435 allResident = GL_FALSE;
436 for (j = 0; j < i; j++)
437 residences[j] = GL_TRUE;
438 }
439 residences[i] = GL_FALSE;
440 }
441 }
442
443 return allResident;
444 }
445
446
447 /**
448 * Request that a set of programs be resident in hardware.
449 * \note Called from the GL API dispatcher.
450 */
451 void
452 _mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
453 {
454 GLint i;
455 GET_CURRENT_CONTEXT(ctx);
456 ASSERT_OUTSIDE_BEGIN_END(ctx);
457
458 if (n < 0) {
459 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
460 return;
461 }
462
463 /* just error checking for now */
464 for (i = 0; i < n; i++) {
465 struct program *prog;
466
467 if (ids[i] == 0) {
468 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
469 return;
470 }
471
472 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
473
474 if (!prog) {
475 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
476 return;
477 }
478
479 prog->Resident = GL_TRUE;
480 }
481 }
482
483
484 /**
485 * Get a program parameter register.
486 * \note Not compiled into display lists.
487 * \note Called from the GL API dispatcher.
488 */
489 void
490 _mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
491 GLenum pname, GLfloat *params)
492 {
493 GET_CURRENT_CONTEXT(ctx);
494 ASSERT_OUTSIDE_BEGIN_END(ctx);
495
496 if (target == GL_VERTEX_PROGRAM_NV) {
497 if (pname == GL_PROGRAM_PARAMETER_NV) {
498 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
499 index += VP_PROG_REG_START;
500 COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
501 }
502 else {
503 _mesa_error(ctx, GL_INVALID_VALUE,
504 "glGetProgramParameterfvNV(index)");
505 return;
506 }
507 }
508 else {
509 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
510 return;
511 }
512 }
513 else {
514 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
515 return;
516 }
517 }
518
519
520 /**
521 * Get a program parameter register.
522 * \note Not compiled into display lists.
523 * \note Called from the GL API dispatcher.
524 */
525 void
526 _mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
527 GLenum pname, GLdouble *params)
528 {
529 GET_CURRENT_CONTEXT(ctx);
530 ASSERT_OUTSIDE_BEGIN_END(ctx);
531
532 if (target == GL_VERTEX_PROGRAM_NV) {
533 if (pname == GL_PROGRAM_PARAMETER_NV) {
534 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
535 index += VP_PROG_REG_START;
536 COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
537 }
538 else {
539 _mesa_error(ctx, GL_INVALID_VALUE,
540 "glGetProgramParameterdvNV(index)");
541 return;
542 }
543 }
544 else {
545 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
546 return;
547 }
548 }
549 else {
550 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
551 return;
552 }
553 }
554
555
556 /**
557 * Get a program attribute.
558 * \note Not compiled into display lists.
559 * \note Called from the GL API dispatcher.
560 */
561 void
562 _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
563 {
564 struct program *prog;
565 GET_CURRENT_CONTEXT(ctx);
566 ASSERT_OUTSIDE_BEGIN_END(ctx);
567
568 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
569 if (!prog) {
570 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
571 return;
572 }
573
574 switch (pname) {
575 case GL_PROGRAM_TARGET_NV:
576 *params = prog->Target;
577 return;
578 case GL_PROGRAM_LENGTH_NV:
579 *params = prog->String ? _mesa_strlen((char *) prog->String) : 0;
580 return;
581 case GL_PROGRAM_RESIDENT_NV:
582 *params = prog->Resident;
583 return;
584 default:
585 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
586 return;
587 }
588 }
589
590
591 /**
592 * Get the program source code.
593 * \note Not compiled into display lists.
594 * \note Called from the GL API dispatcher.
595 */
596 void
597 _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
598 {
599 struct program *prog;
600 GET_CURRENT_CONTEXT(ctx);
601 ASSERT_OUTSIDE_BEGIN_END(ctx);
602
603 if (pname != GL_PROGRAM_STRING_NV) {
604 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
605 return;
606 }
607
608 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
609 if (!prog) {
610 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
611 return;
612 }
613
614 if (prog->String) {
615 MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
616 }
617 else {
618 program[0] = 0;
619 }
620 }
621
622
623 /**
624 * Get matrix tracking information.
625 * \note Not compiled into display lists.
626 * \note Called from the GL API dispatcher.
627 */
628 void
629 _mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
630 GLenum pname, GLint *params)
631 {
632 GET_CURRENT_CONTEXT(ctx);
633 ASSERT_OUTSIDE_BEGIN_END(ctx);
634
635 if (target == GL_VERTEX_PROGRAM_NV
636 && ctx->Extensions.NV_vertex_program) {
637 GLuint i;
638
639 if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
640 _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
641 return;
642 }
643
644 i = address / 4;
645
646 switch (pname) {
647 case GL_TRACK_MATRIX_NV:
648 params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
649 return;
650 case GL_TRACK_MATRIX_TRANSFORM_NV:
651 params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
652 return;
653 default:
654 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
655 return;
656 }
657 }
658 else {
659 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
660 return;
661 }
662 }
663
664
665 /**
666 * Get a vertex (or vertex array) attribute.
667 * \note Not compiled into display lists.
668 * \note Called from the GL API dispatcher.
669 */
670 void
671 _mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
672 {
673 GET_CURRENT_CONTEXT(ctx);
674 ASSERT_OUTSIDE_BEGIN_END(ctx);
675
676 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
677 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
678 return;
679 }
680
681 switch (pname) {
682 case GL_ATTRIB_ARRAY_SIZE_NV:
683 params[0] = ctx->Array.VertexAttrib[index].Size;
684 break;
685 case GL_ATTRIB_ARRAY_STRIDE_NV:
686 params[0] = ctx->Array.VertexAttrib[index].Stride;
687 break;
688 case GL_ATTRIB_ARRAY_TYPE_NV:
689 params[0] = ctx->Array.VertexAttrib[index].Type;
690 break;
691 case GL_CURRENT_ATTRIB_NV:
692 COPY_4V(params, ctx->Current.Attrib[index]);
693 break;
694 default:
695 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
696 return;
697 }
698 }
699
700 /**
701 * Get a vertex (or vertex array) attribute.
702 * \note Not compiled into display lists.
703 * \note Called from the GL API dispatcher.
704 */
705 void
706 _mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
707 {
708 GET_CURRENT_CONTEXT(ctx);
709 ASSERT_OUTSIDE_BEGIN_END(ctx);
710
711 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
712 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
713 return;
714 }
715
716 switch (pname) {
717 case GL_ATTRIB_ARRAY_SIZE_NV:
718 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
719 break;
720 case GL_ATTRIB_ARRAY_STRIDE_NV:
721 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
722 break;
723 case GL_ATTRIB_ARRAY_TYPE_NV:
724 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
725 break;
726 case GL_CURRENT_ATTRIB_NV:
727 COPY_4V(params, ctx->Current.Attrib[index]);
728 break;
729 default:
730 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
731 return;
732 }
733 }
734
735 /**
736 * Get a vertex (or vertex array) attribute.
737 * \note Not compiled into display lists.
738 * \note Called from the GL API dispatcher.
739 */
740 void
741 _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
742 {
743 GET_CURRENT_CONTEXT(ctx);
744 ASSERT_OUTSIDE_BEGIN_END(ctx);
745
746 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
747 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
748 return;
749 }
750
751 switch (pname) {
752 case GL_ATTRIB_ARRAY_SIZE_NV:
753 params[0] = ctx->Array.VertexAttrib[index].Size;
754 break;
755 case GL_ATTRIB_ARRAY_STRIDE_NV:
756 params[0] = ctx->Array.VertexAttrib[index].Stride;
757 break;
758 case GL_ATTRIB_ARRAY_TYPE_NV:
759 params[0] = ctx->Array.VertexAttrib[index].Type;
760 break;
761 case GL_CURRENT_ATTRIB_NV:
762 COPY_4V_CAST(params, ctx->Current.Attrib[index], GLint);
763 break;
764 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
765 if (!ctx->Extensions.ARB_vertex_buffer_object) {
766 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
767 return;
768 }
769 params[0] = ctx->Array.VertexAttribArrayBufferBinding[index];
770 break;
771 default:
772 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
773 return;
774 }
775 }
776
777
778 /**
779 * Get a vertex array attribute pointer.
780 * \note Not compiled into display lists.
781 * \note Called from the GL API dispatcher.
782 */
783 void
784 _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
785 {
786 GET_CURRENT_CONTEXT(ctx);
787 ASSERT_OUTSIDE_BEGIN_END(ctx);
788
789 if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
790 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
791 return;
792 }
793
794 if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
795 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
796 return;
797 }
798
799 *pointer = ctx->Array.VertexAttrib[index].Ptr;;
800 }
801
802
803 /**
804 * Determine if id names a program.
805 * \note Not compiled into display lists.
806 * \note Called from both glIsProgramNV and glIsProgramARB.
807 * \param id is the program identifier
808 * \return GL_TRUE if id is a program, else GL_FALSE.
809 */
810 GLboolean
811 _mesa_IsProgramNV(GLuint id)
812 {
813 struct program *prog;
814 GET_CURRENT_CONTEXT(ctx);
815 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
816
817 if (id == 0)
818 return GL_FALSE;
819
820 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
821 if (prog && prog->Target)
822 return GL_TRUE;
823 else
824 return GL_FALSE;
825 }
826
827
828 /**
829 * Load/parse/compile a program.
830 * \note Called from the GL API dispatcher.
831 */
832 void
833 _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
834 const GLubyte *program)
835 {
836 struct program *prog;
837 GET_CURRENT_CONTEXT(ctx);
838 ASSERT_OUTSIDE_BEGIN_END(ctx);
839
840 if (id == 0) {
841 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
842 return;
843 }
844
845 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
846
847 if (prog && prog->Target != 0 && prog->Target != target) {
848 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
849 return;
850 }
851
852 if ((target == GL_VERTEX_PROGRAM_NV ||
853 target == GL_VERTEX_STATE_PROGRAM_NV)
854 && ctx->Extensions.NV_vertex_program) {
855 struct vertex_program *vprog = (struct vertex_program *) prog;
856 if (!vprog) {
857 vprog = CALLOC_STRUCT(vertex_program);
858 if (!vprog) {
859 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
860 return;
861 }
862 vprog->Base.RefCount = 1;
863 vprog->Base.Resident = GL_TRUE;
864 _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
865 }
866 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
867 }
868 else if (target == GL_FRAGMENT_PROGRAM_NV
869 && ctx->Extensions.NV_fragment_program) {
870 struct fragment_program *fprog = (struct fragment_program *) prog;
871 if (!fprog) {
872 fprog = CALLOC_STRUCT(fragment_program);
873 if (!fprog) {
874 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
875 return;
876 }
877 fprog->Base.RefCount = 1;
878 fprog->Base.Resident = GL_TRUE;
879 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
880 }
881 _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
882 }
883 else {
884 _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
885 }
886 }
887
888
889
890 /**
891 * Set a program parameter register.
892 * \note Called from the GL API dispatcher.
893 */
894 void
895 _mesa_ProgramParameter4dNV(GLenum target, GLuint index,
896 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
897 {
898 _mesa_ProgramParameter4fNV(target, index,
899 (GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
900 }
901
902
903 /**
904 * Set a program parameter register.
905 * \note Called from the GL API dispatcher.
906 */
907 void
908 _mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
909 const GLdouble *params)
910 {
911 _mesa_ProgramParameter4fNV(target, index,
912 (GLfloat)params[0], (GLfloat)params[1],
913 (GLfloat)params[2], (GLfloat)params[3]);
914 }
915
916
917 /**
918 * Set a program parameter register.
919 * \note Called from the GL API dispatcher.
920 */
921 void
922 _mesa_ProgramParameter4fNV(GLenum target, GLuint index,
923 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
924 {
925 GET_CURRENT_CONTEXT(ctx);
926 ASSERT_OUTSIDE_BEGIN_END(ctx);
927
928 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
929 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
930 index += VP_PROG_REG_START;
931 ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
932 }
933 else {
934 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameterNV(index)");
935 return;
936 }
937 }
938 else {
939 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameterNV");
940 return;
941 }
942 }
943
944
945 /**
946 * Set a program parameter register.
947 * \note Called from the GL API dispatcher.
948 */
949 void
950 _mesa_ProgramParameter4fvNV(GLenum target, GLuint index,
951 const GLfloat *params)
952 {
953 _mesa_ProgramParameter4fNV(target, index,
954 params[0], params[1], params[2], params[3]);
955 }
956
957
958
959 /**
960 * Set a sequence of program parameter registers.
961 * \note Called from the GL API dispatcher.
962 */
963 void
964 _mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
965 GLuint num, const GLdouble *params)
966 {
967 GET_CURRENT_CONTEXT(ctx);
968 ASSERT_OUTSIDE_BEGIN_END(ctx);
969
970 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
971 GLuint i;
972 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
973 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
974 return;
975 }
976 index += VP_PROG_REG_START;
977 for (i = 0; i < num; i++) {
978 COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index + i],
979 params, GLfloat);
980 params += 4;
981 };
982 }
983 else {
984 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
985 return;
986 }
987 }
988
989
990 /**
991 * Set a sequence of program parameter registers.
992 * \note Called from the GL API dispatcher.
993 */
994 void
995 _mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
996 GLuint num, const GLfloat *params)
997 {
998 GET_CURRENT_CONTEXT(ctx);
999 ASSERT_OUTSIDE_BEGIN_END(ctx);
1000
1001 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1002 GLuint i;
1003 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
1004 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
1005 return;
1006 }
1007 index += VP_PROG_REG_START;
1008 for (i = 0; i < num; i++) {
1009 COPY_4V(ctx->VertexProgram.Machine.Registers[index + i], params);
1010 params += 4;
1011 };
1012 }
1013 else {
1014 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
1015 return;
1016 }
1017 }
1018
1019
1020
1021 /**
1022 * Setup tracking of matrices into program parameter registers.
1023 * \note Called from the GL API dispatcher.
1024 */
1025 void
1026 _mesa_TrackMatrixNV(GLenum target, GLuint address,
1027 GLenum matrix, GLenum transform)
1028 {
1029 GET_CURRENT_CONTEXT(ctx);
1030 ASSERT_OUTSIDE_BEGIN_END(ctx);
1031
1032 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1033 if (address & 0x3) {
1034 /* addr must be multiple of four */
1035 _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
1036 return;
1037 }
1038
1039 switch (matrix) {
1040 case GL_NONE:
1041 case GL_MODELVIEW:
1042 case GL_PROJECTION:
1043 case GL_TEXTURE:
1044 case GL_COLOR:
1045 case GL_MODELVIEW_PROJECTION_NV:
1046 case GL_MATRIX0_NV:
1047 case GL_MATRIX1_NV:
1048 case GL_MATRIX2_NV:
1049 case GL_MATRIX3_NV:
1050 case GL_MATRIX4_NV:
1051 case GL_MATRIX5_NV:
1052 case GL_MATRIX6_NV:
1053 case GL_MATRIX7_NV:
1054 /* OK, fallthrough */
1055 break;
1056 default:
1057 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
1058 return;
1059 }
1060
1061 switch (transform) {
1062 case GL_IDENTITY_NV:
1063 case GL_INVERSE_NV:
1064 case GL_TRANSPOSE_NV:
1065 case GL_INVERSE_TRANSPOSE_NV:
1066 /* OK, fallthrough */
1067 break;
1068 default:
1069 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
1070 return;
1071 }
1072
1073 ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
1074 ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
1075 }
1076 else {
1077 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
1078 return;
1079 }
1080 }
1081
1082
1083 void
1084 _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
1085 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1086 {
1087 struct program *prog;
1088 struct fragment_program *fragProg;
1089 GLint i;
1090 GET_CURRENT_CONTEXT(ctx);
1091 ASSERT_OUTSIDE_BEGIN_END(ctx);
1092
1093 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1094 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1095 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
1096 return;
1097 }
1098
1099 if (len <= 0) {
1100 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1101 return;
1102 }
1103
1104 fragProg = (struct fragment_program *) prog;
1105 for (i = 0; i < fragProg->NumParameters; i++) {
1106 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1107 (const char *) name, len) &&
1108 fragProg->Parameters[i].Name[len] == 0) {
1109 ASSERT(!fragProg->Parameters[i].Constant);
1110 fragProg->Parameters[i].Values[0] = x;
1111 fragProg->Parameters[i].Values[1] = y;
1112 fragProg->Parameters[i].Values[2] = z;
1113 fragProg->Parameters[i].Values[3] = w;
1114 return;
1115 }
1116 }
1117
1118 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1119 }
1120
1121
1122 void
1123 _mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
1124 const float v[])
1125 {
1126 _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
1127 }
1128
1129
1130 void
1131 _mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
1132 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
1133 {
1134 _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
1135 (GLfloat)z, (GLfloat)w);
1136 }
1137
1138
1139 void
1140 _mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
1141 const double v[])
1142 {
1143 _mesa_ProgramNamedParameter4fNV(id, len, name,
1144 (GLfloat)v[0], (GLfloat)v[1],
1145 (GLfloat)v[2], (GLfloat)v[3]);
1146 }
1147
1148
1149 void
1150 _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
1151 GLfloat *params)
1152 {
1153 struct program *prog;
1154 struct fragment_program *fragProg;
1155 GLint i;
1156 GET_CURRENT_CONTEXT(ctx);
1157 ASSERT_OUTSIDE_BEGIN_END(ctx);
1158
1159 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1160 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1161 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
1162 return;
1163 }
1164
1165 if (len <= 0) {
1166 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1167 return;
1168 }
1169
1170 fragProg = (struct fragment_program *) prog;
1171 for (i = 0; i < fragProg->NumParameters; i++) {
1172 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1173 (const char *) name, len) &&
1174 fragProg->Parameters[i].Name[len] == 0) {
1175 ASSERT(!fragProg->Parameters[i].Constant);
1176 params[0] = fragProg->Parameters[i].Values[0];
1177 params[1] = fragProg->Parameters[i].Values[1];
1178 params[2] = fragProg->Parameters[i].Values[2];
1179 params[3] = fragProg->Parameters[i].Values[3];
1180 return;
1181 }
1182 }
1183
1184 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1185 }
1186
1187
1188 void
1189 _mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
1190 GLdouble *params)
1191 {
1192 GLfloat floatParams[4];
1193 _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
1194 COPY_4V(params, floatParams);
1195 }
1196
1197
1198 #if 000
1199 void
1200 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
1201 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1202 {
1203 GET_CURRENT_CONTEXT(ctx);
1204 ASSERT_OUTSIDE_BEGIN_END(ctx);
1205
1206 if (target == GL_FRAGMENT_PROGRAM_NV) {
1207 struct fragment_program *fprog = ctx->FragmentProgram.Current;
1208 if (!fprog) {
1209 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
1210 return;
1211 }
1212 if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
1213 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
1214 return;
1215 }
1216 fprog->Base.LocalParams[index][0] = x;
1217 fprog->Base.LocalParams[index][1] = y;
1218 fprog->Base.LocalParams[index][2] = z;
1219 fprog->Base.LocalParams[index][3] = w;
1220 }
1221 else {
1222 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
1223 return;
1224 }
1225 }
1226
1227
1228 /* XXX move into arbprogram.c */
1229 void
1230 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
1231 const GLfloat *params)
1232 {
1233 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
1234 params[2], params[3]);
1235 }
1236
1237
1238 /* XXX move into arbprogram.c */
1239 void
1240 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
1241 GLdouble x, GLdouble y,
1242 GLdouble z, GLdouble w)
1243 {
1244 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat)x, (GLfloat)y,
1245 (GLfloat)z, (GLfloat)w);
1246 }
1247
1248
1249 /* XXX move into arbprogram.c */
1250 void
1251 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
1252 const GLdouble *params)
1253 {
1254 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat)params[0],
1255 (GLfloat)params[1], (GLfloat)params[2],
1256 (GLfloat)params[3]);
1257 }
1258
1259
1260 /* XXX move into arbprogram.c */
1261 void
1262 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
1263 GLfloat *params)
1264 {
1265 GET_CURRENT_CONTEXT(ctx);
1266 ASSERT_OUTSIDE_BEGIN_END(ctx);
1267
1268 if (target == GL_FRAGMENT_PROGRAM_NV) {
1269 struct fragment_program *fprog = ctx->FragmentProgram.Current;
1270 if (!fprog) {
1271 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
1272 return;
1273 }
1274 if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
1275 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramLocalParameterARB");
1276 return;
1277 }
1278 params[0] = fprog->Base.LocalParams[index][0];
1279 params[1] = fprog->Base.LocalParams[index][1];
1280 params[2] = fprog->Base.LocalParams[index][2];
1281 params[3] = fprog->Base.LocalParams[index][3];
1282 }
1283 else {
1284 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
1285 return;
1286 }
1287 }
1288
1289
1290 /* XXX move into arbprogram.c */
1291 void
1292 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
1293 GLdouble *params)
1294 {
1295 GLfloat floatParams[4];
1296 _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
1297 COPY_4V(params, floatParams);
1298 }
1299 #endif