Implement debugger callback, etc for vertex programs. Misc clean-ups.
[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 * 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 by both glBindProgramNV
182 * and glBindProgramARB.
183 */
184 void
185 _mesa_BindProgramNV(GLenum target, GLuint id)
186 {
187 struct program *prog;
188 GET_CURRENT_CONTEXT(ctx);
189 ASSERT_OUTSIDE_BEGIN_END(ctx);
190
191 if ((target == GL_VERTEX_PROGRAM_NV
192 && ctx->Extensions.NV_vertex_program) ||
193 (target == GL_VERTEX_PROGRAM_ARB
194 && ctx->Extensions.ARB_vertex_program)) {
195 if (ctx->VertexProgram.Current &&
196 ctx->VertexProgram.Current->Base.Id == id)
197 return;
198 /* decrement refcount on previously bound vertex program */
199 if (ctx->VertexProgram.Current) {
200 ctx->VertexProgram.Current->Base.RefCount--;
201 /* and delete if refcount goes below one */
202 if (ctx->VertexProgram.Current->Base.RefCount <= 0) {
203 _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base));
204 _mesa_HashRemove(ctx->Shared->Programs, id);
205 }
206 }
207 }
208 else if ((target == GL_FRAGMENT_PROGRAM_NV
209 && ctx->Extensions.NV_fragment_program) ||
210 (target == GL_FRAGMENT_PROGRAM_ARB
211 && ctx->Extensions.ARB_fragment_program)) {
212 if (ctx->FragmentProgram.Current &&
213 ctx->FragmentProgram.Current->Base.Id == id)
214 return;
215 /* decrement refcount on previously bound fragment program */
216 if (ctx->FragmentProgram.Current) {
217 ctx->FragmentProgram.Current->Base.RefCount--;
218 /* and delete if refcount goes below one */
219 if (ctx->FragmentProgram.Current->Base.RefCount <= 0) {
220 _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base));
221 _mesa_HashRemove(ctx->Shared->Programs, id);
222 }
223 }
224 }
225 else {
226 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
227 return;
228 }
229
230 /* NOTE: binding to a non-existant program is not an error.
231 * That's supposed to be caught in glBegin.
232 */
233 if (id == 0) {
234 /* default program */
235 prog = NULL;
236 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
237 prog = ctx->Shared->DefaultVertexProgram;
238 else
239 prog = ctx->Shared->DefaultFragmentProgram;
240 }
241 else {
242 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
243 if (prog) {
244 if (prog->Target == 0) {
245 /* prog was allocated with glGenProgramsNV */
246 prog->Target = target;
247 }
248 else if (prog->Target != target) {
249 _mesa_error(ctx, GL_INVALID_OPERATION,
250 "glBindProgramNV/ARB(target mismatch)");
251 return;
252 }
253 }
254 else {
255 /* allocate a new program now */
256 prog = _mesa_alloc_program(ctx, target, id);
257 if (!prog) {
258 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
259 return;
260 }
261 prog->Id = id;
262 prog->Target = target;
263 prog->Resident = GL_TRUE;
264 prog->RefCount = 1;
265 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
266 }
267 }
268
269 /* bind now */
270 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
271 ctx->VertexProgram.Current = (struct vertex_program *) prog;
272 }
273 else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
274 ctx->FragmentProgram.Current = (struct fragment_program *) prog;
275 }
276
277 if (prog)
278 prog->RefCount++;
279 }
280
281
282 /**
283 * Delete a list of programs.
284 * \note Not compiled into display lists.
285 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
286 */
287 void
288 _mesa_DeleteProgramsNV(GLsizei n, const GLuint *ids)
289 {
290 GLint i;
291 GET_CURRENT_CONTEXT(ctx);
292 ASSERT_OUTSIDE_BEGIN_END(ctx);
293
294 if (n < 0) {
295 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
296 return;
297 }
298
299 for (i = 0; i < n; i++) {
300 if (ids[i] != 0) {
301 struct program *prog = (struct program *)
302 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
303 if (prog) {
304 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
305 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
306 if (ctx->VertexProgram.Current &&
307 ctx->VertexProgram.Current->Base.Id == ids[i]) {
308 /* unbind this currently bound program */
309 _mesa_BindProgramNV(prog->Target, 0);
310 }
311 }
312 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
313 if (ctx->FragmentProgram.Current &&
314 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
315 /* unbind this currently bound program */
316 _mesa_BindProgramNV(prog->Target, 0);
317 }
318 }
319 else {
320 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
321 return;
322 }
323 prog->RefCount--;
324 if (prog->RefCount <= 0) {
325 _mesa_delete_program(ctx, prog);
326 }
327 }
328 }
329 }
330 }
331
332
333 /**
334 * Execute a vertex state program.
335 * \note Called from the GL API dispatcher.
336 */
337 void
338 _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
339 {
340 struct vertex_program *vprog;
341 GET_CURRENT_CONTEXT(ctx);
342 ASSERT_OUTSIDE_BEGIN_END(ctx);
343
344 if (target != GL_VERTEX_STATE_PROGRAM_NV) {
345 _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV");
346 return;
347 }
348
349 vprog = (struct vertex_program *)
350 _mesa_HashLookup(ctx->Shared->Programs, id);
351
352 if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
353 _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
354 return;
355 }
356
357 _mesa_init_vp_registers(ctx);
358 _mesa_init_tracked_matrices(ctx);
359 COPY_4V(ctx->VertexProgram.Machine.Registers[VP_INPUT_REG_START], params);
360 _mesa_exec_vertex_program(ctx, vprog);
361 }
362
363
364 /**
365 * Generate a list of new program identifiers.
366 * \note Not compiled into display lists.
367 * \note Called by both glGenProgramsNV and glGenProgramsARB.
368 */
369 void
370 _mesa_GenProgramsNV(GLsizei n, GLuint *ids)
371 {
372 GLuint first;
373 GLuint i;
374 GET_CURRENT_CONTEXT(ctx);
375 ASSERT_OUTSIDE_BEGIN_END(ctx);
376
377 if (n < 0) {
378 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
379 return;
380 }
381
382 if (!ids)
383 return;
384
385 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
386
387 for (i = 0; i < (GLuint) n; i++) {
388 const int bytes = MAX2(sizeof(struct vertex_program),
389 sizeof(struct fragment_program));
390 struct program *prog = (struct program *) _mesa_calloc(bytes);
391 if (!prog) {
392 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms");
393 return;
394 }
395 prog->RefCount = 1;
396 prog->Id = first + i;
397 _mesa_HashInsert(ctx->Shared->Programs, first + i, prog);
398 }
399
400 /* Return the program names */
401 for (i = 0; i < (GLuint) n; i++) {
402 ids[i] = first + i;
403 }
404 }
405
406
407 /**
408 * Determine if a set of programs is resident in hardware.
409 * \note Not compiled into display lists.
410 * \note Called from the GL API dispatcher.
411 */
412 GLboolean _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
413 GLboolean *residences)
414 {
415 GLint i, j;
416 GLboolean allResident = GL_TRUE;
417 GET_CURRENT_CONTEXT(ctx);
418 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
419
420 if (n < 0) {
421 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
422 return GL_FALSE;
423 }
424
425 for (i = 0; i < n; i++) {
426 const struct program *prog;
427 if (ids[i] == 0) {
428 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
429 return GL_FALSE;
430 }
431 prog = (const struct program *)
432 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
433 if (!prog) {
434 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
435 return GL_FALSE;
436 }
437 if (prog->Resident) {
438 if (!allResident)
439 residences[i] = GL_TRUE;
440 }
441 else {
442 if (allResident) {
443 allResident = GL_FALSE;
444 for (j = 0; j < i; j++)
445 residences[j] = GL_TRUE;
446 }
447 residences[i] = GL_FALSE;
448 }
449 }
450
451 return allResident;
452 }
453
454
455 /**
456 * Request that a set of programs be resident in hardware.
457 * \note Called from the GL API dispatcher.
458 */
459 void
460 _mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
461 {
462 GLint i;
463 GET_CURRENT_CONTEXT(ctx);
464 ASSERT_OUTSIDE_BEGIN_END(ctx);
465
466 if (n < 0) {
467 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
468 return;
469 }
470
471 /* just error checking for now */
472 for (i = 0; i < n; i++) {
473 struct program *prog;
474
475 if (ids[i] == 0) {
476 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
477 return;
478 }
479
480 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
481
482 if (!prog) {
483 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
484 return;
485 }
486
487 prog->Resident = GL_TRUE;
488 }
489 }
490
491
492 /**
493 * Get a program parameter register.
494 * \note Not compiled into display lists.
495 * \note Called from the GL API dispatcher.
496 */
497 void
498 _mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
499 GLenum pname, GLfloat *params)
500 {
501 GET_CURRENT_CONTEXT(ctx);
502 ASSERT_OUTSIDE_BEGIN_END(ctx);
503
504 if (target == GL_VERTEX_PROGRAM_NV) {
505 if (pname == GL_PROGRAM_PARAMETER_NV) {
506 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
507 index += VP_PROG_REG_START;
508 COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
509 }
510 else {
511 _mesa_error(ctx, GL_INVALID_VALUE,
512 "glGetProgramParameterfvNV(index)");
513 return;
514 }
515 }
516 else {
517 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
518 return;
519 }
520 }
521 else {
522 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
523 return;
524 }
525 }
526
527
528 /**
529 * Get a program parameter register.
530 * \note Not compiled into display lists.
531 * \note Called from the GL API dispatcher.
532 */
533 void
534 _mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
535 GLenum pname, GLdouble *params)
536 {
537 GET_CURRENT_CONTEXT(ctx);
538 ASSERT_OUTSIDE_BEGIN_END(ctx);
539
540 if (target == GL_VERTEX_PROGRAM_NV) {
541 if (pname == GL_PROGRAM_PARAMETER_NV) {
542 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
543 index += VP_PROG_REG_START;
544 COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
545 }
546 else {
547 _mesa_error(ctx, GL_INVALID_VALUE,
548 "glGetProgramParameterdvNV(index)");
549 return;
550 }
551 }
552 else {
553 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
554 return;
555 }
556 }
557 else {
558 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
559 return;
560 }
561 }
562
563
564 /**
565 * Get a program attribute.
566 * \note Not compiled into display lists.
567 * \note Called from the GL API dispatcher.
568 */
569 void
570 _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
571 {
572 struct program *prog;
573 GET_CURRENT_CONTEXT(ctx);
574
575 if (!ctx->_CurrentProgram)
576 ASSERT_OUTSIDE_BEGIN_END(ctx);
577
578 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
579 if (!prog) {
580 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
581 return;
582 }
583
584 switch (pname) {
585 case GL_PROGRAM_TARGET_NV:
586 *params = prog->Target;
587 return;
588 case GL_PROGRAM_LENGTH_NV:
589 *params = prog->String ? _mesa_strlen((char *) prog->String) : 0;
590 return;
591 case GL_PROGRAM_RESIDENT_NV:
592 *params = prog->Resident;
593 return;
594 default:
595 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
596 return;
597 }
598 }
599
600
601 /**
602 * Get the program source code.
603 * \note Not compiled into display lists.
604 * \note Called from the GL API dispatcher.
605 */
606 void
607 _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
608 {
609 struct program *prog;
610 GET_CURRENT_CONTEXT(ctx);
611
612 if (!ctx->_CurrentProgram)
613 ASSERT_OUTSIDE_BEGIN_END(ctx);
614
615 if (pname != GL_PROGRAM_STRING_NV) {
616 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
617 return;
618 }
619
620 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
621 if (!prog) {
622 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
623 return;
624 }
625
626 if (prog->String) {
627 MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
628 }
629 else {
630 program[0] = 0;
631 }
632 }
633
634
635 /**
636 * Get matrix tracking information.
637 * \note Not compiled into display lists.
638 * \note Called from the GL API dispatcher.
639 */
640 void
641 _mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
642 GLenum pname, GLint *params)
643 {
644 GET_CURRENT_CONTEXT(ctx);
645 ASSERT_OUTSIDE_BEGIN_END(ctx);
646
647 if (target == GL_VERTEX_PROGRAM_NV
648 && ctx->Extensions.NV_vertex_program) {
649 GLuint i;
650
651 if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
652 _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
653 return;
654 }
655
656 i = address / 4;
657
658 switch (pname) {
659 case GL_TRACK_MATRIX_NV:
660 params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
661 return;
662 case GL_TRACK_MATRIX_TRANSFORM_NV:
663 params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
664 return;
665 default:
666 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
667 return;
668 }
669 }
670 else {
671 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
672 return;
673 }
674 }
675
676
677 /**
678 * Get a vertex (or vertex array) attribute.
679 * \note Not compiled into display lists.
680 * \note Called from the GL API dispatcher.
681 */
682 void
683 _mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
684 {
685 GET_CURRENT_CONTEXT(ctx);
686 ASSERT_OUTSIDE_BEGIN_END(ctx);
687
688 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
689 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
690 return;
691 }
692
693 switch (pname) {
694 case GL_ATTRIB_ARRAY_SIZE_NV:
695 params[0] = ctx->Array.VertexAttrib[index].Size;
696 break;
697 case GL_ATTRIB_ARRAY_STRIDE_NV:
698 params[0] = ctx->Array.VertexAttrib[index].Stride;
699 break;
700 case GL_ATTRIB_ARRAY_TYPE_NV:
701 params[0] = ctx->Array.VertexAttrib[index].Type;
702 break;
703 case GL_CURRENT_ATTRIB_NV:
704 FLUSH_CURRENT(ctx, 0);
705 COPY_4V(params, ctx->Current.Attrib[index]);
706 break;
707 default:
708 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
709 return;
710 }
711 }
712
713 /**
714 * Get a vertex (or vertex array) attribute.
715 * \note Not compiled into display lists.
716 * \note Called from the GL API dispatcher.
717 */
718 void
719 _mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
720 {
721 GET_CURRENT_CONTEXT(ctx);
722 ASSERT_OUTSIDE_BEGIN_END(ctx);
723
724 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
725 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
726 return;
727 }
728
729 switch (pname) {
730 case GL_ATTRIB_ARRAY_SIZE_NV:
731 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
732 break;
733 case GL_ATTRIB_ARRAY_STRIDE_NV:
734 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
735 break;
736 case GL_ATTRIB_ARRAY_TYPE_NV:
737 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
738 break;
739 case GL_CURRENT_ATTRIB_NV:
740 FLUSH_CURRENT(ctx, 0);
741 COPY_4V(params, ctx->Current.Attrib[index]);
742 break;
743 default:
744 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
745 return;
746 }
747 }
748
749 /**
750 * Get a vertex (or vertex array) attribute.
751 * \note Not compiled into display lists.
752 * \note Called from the GL API dispatcher.
753 */
754 void
755 _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
756 {
757 GET_CURRENT_CONTEXT(ctx);
758 ASSERT_OUTSIDE_BEGIN_END(ctx);
759
760 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
761 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
762 return;
763 }
764
765 switch (pname) {
766 case GL_ATTRIB_ARRAY_SIZE_NV:
767 params[0] = ctx->Array.VertexAttrib[index].Size;
768 break;
769 case GL_ATTRIB_ARRAY_STRIDE_NV:
770 params[0] = ctx->Array.VertexAttrib[index].Stride;
771 break;
772 case GL_ATTRIB_ARRAY_TYPE_NV:
773 params[0] = ctx->Array.VertexAttrib[index].Type;
774 break;
775 case GL_CURRENT_ATTRIB_NV:
776 FLUSH_CURRENT(ctx, 0);
777 COPY_4V_CAST(params, ctx->Current.Attrib[index], GLint);
778 break;
779 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
780 if (!ctx->Extensions.ARB_vertex_buffer_object) {
781 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
782 return;
783 }
784 params[0] = ctx->Array.VertexAttribArrayBufferBinding[index];
785 break;
786 default:
787 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
788 return;
789 }
790 }
791
792
793 /**
794 * Get a vertex array attribute pointer.
795 * \note Not compiled into display lists.
796 * \note Called from the GL API dispatcher.
797 */
798 void
799 _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
800 {
801 GET_CURRENT_CONTEXT(ctx);
802 ASSERT_OUTSIDE_BEGIN_END(ctx);
803
804 if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
805 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
806 return;
807 }
808
809 if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
810 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
811 return;
812 }
813
814 *pointer = ctx->Array.VertexAttrib[index].Ptr;;
815 }
816
817
818 /**
819 * Determine if id names a program.
820 * \note Not compiled into display lists.
821 * \note Called from both glIsProgramNV and glIsProgramARB.
822 * \param id is the program identifier
823 * \return GL_TRUE if id is a program, else GL_FALSE.
824 */
825 GLboolean
826 _mesa_IsProgramNV(GLuint id)
827 {
828 struct program *prog;
829 GET_CURRENT_CONTEXT(ctx);
830 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
831
832 if (id == 0)
833 return GL_FALSE;
834
835 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
836 if (prog && prog->Target)
837 return GL_TRUE;
838 else
839 return GL_FALSE;
840 }
841
842
843 /**
844 * Load/parse/compile a program.
845 * \note Called from the GL API dispatcher.
846 */
847 void
848 _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
849 const GLubyte *program)
850 {
851 struct program *prog;
852 GET_CURRENT_CONTEXT(ctx);
853 ASSERT_OUTSIDE_BEGIN_END(ctx);
854
855 if (id == 0) {
856 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
857 return;
858 }
859
860 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
861
862 if (prog && prog->Target != 0 && prog->Target != target) {
863 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
864 return;
865 }
866
867 if ((target == GL_VERTEX_PROGRAM_NV ||
868 target == GL_VERTEX_STATE_PROGRAM_NV)
869 && ctx->Extensions.NV_vertex_program) {
870 struct vertex_program *vprog = (struct vertex_program *) prog;
871 if (!vprog) {
872 vprog = CALLOC_STRUCT(vertex_program);
873 if (!vprog) {
874 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
875 return;
876 }
877 vprog->Base.RefCount = 1;
878 vprog->Base.Resident = GL_TRUE;
879 _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
880 }
881 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
882 }
883 else if (target == GL_FRAGMENT_PROGRAM_NV
884 && ctx->Extensions.NV_fragment_program) {
885 struct fragment_program *fprog = (struct fragment_program *) prog;
886 if (!fprog) {
887 fprog = CALLOC_STRUCT(fragment_program);
888 if (!fprog) {
889 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
890 return;
891 }
892 fprog->Base.RefCount = 1;
893 fprog->Base.Resident = GL_TRUE;
894 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
895 }
896 _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
897 }
898 else {
899 _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
900 }
901 }
902
903
904
905 /**
906 * Set a program parameter register.
907 * \note Called from the GL API dispatcher.
908 */
909 void
910 _mesa_ProgramParameter4dNV(GLenum target, GLuint index,
911 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
912 {
913 _mesa_ProgramParameter4fNV(target, index,
914 (GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
915 }
916
917
918 /**
919 * Set a program parameter register.
920 * \note Called from the GL API dispatcher.
921 */
922 void
923 _mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
924 const GLdouble *params)
925 {
926 _mesa_ProgramParameter4fNV(target, index,
927 (GLfloat)params[0], (GLfloat)params[1],
928 (GLfloat)params[2], (GLfloat)params[3]);
929 }
930
931
932 /**
933 * Set a program parameter register.
934 * \note Called from the GL API dispatcher.
935 */
936 void
937 _mesa_ProgramParameter4fNV(GLenum target, GLuint index,
938 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
939 {
940 GET_CURRENT_CONTEXT(ctx);
941 ASSERT_OUTSIDE_BEGIN_END(ctx);
942
943 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
944 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
945 index += VP_PROG_REG_START;
946 ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
947 }
948 else {
949 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameterNV(index)");
950 return;
951 }
952 }
953 else {
954 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameterNV");
955 return;
956 }
957 }
958
959
960 /**
961 * Set a program parameter register.
962 * \note Called from the GL API dispatcher.
963 */
964 void
965 _mesa_ProgramParameter4fvNV(GLenum target, GLuint index,
966 const GLfloat *params)
967 {
968 _mesa_ProgramParameter4fNV(target, index,
969 params[0], params[1], params[2], params[3]);
970 }
971
972
973
974 /**
975 * Set a sequence of program parameter registers.
976 * \note Called from the GL API dispatcher.
977 */
978 void
979 _mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
980 GLuint num, const GLdouble *params)
981 {
982 GET_CURRENT_CONTEXT(ctx);
983 ASSERT_OUTSIDE_BEGIN_END(ctx);
984
985 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
986 GLuint i;
987 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
988 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
989 return;
990 }
991 index += VP_PROG_REG_START;
992 for (i = 0; i < num; i++) {
993 COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index + i],
994 params, GLfloat);
995 params += 4;
996 };
997 }
998 else {
999 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
1000 return;
1001 }
1002 }
1003
1004
1005 /**
1006 * Set a sequence of program parameter registers.
1007 * \note Called from the GL API dispatcher.
1008 */
1009 void
1010 _mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
1011 GLuint num, const GLfloat *params)
1012 {
1013 GET_CURRENT_CONTEXT(ctx);
1014 ASSERT_OUTSIDE_BEGIN_END(ctx);
1015
1016 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1017 GLuint i;
1018 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
1019 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
1020 return;
1021 }
1022 index += VP_PROG_REG_START;
1023 for (i = 0; i < num; i++) {
1024 COPY_4V(ctx->VertexProgram.Machine.Registers[index + i], params);
1025 params += 4;
1026 };
1027 }
1028 else {
1029 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
1030 return;
1031 }
1032 }
1033
1034
1035
1036 /**
1037 * Setup tracking of matrices into program parameter registers.
1038 * \note Called from the GL API dispatcher.
1039 */
1040 void
1041 _mesa_TrackMatrixNV(GLenum target, GLuint address,
1042 GLenum matrix, GLenum transform)
1043 {
1044 GET_CURRENT_CONTEXT(ctx);
1045 ASSERT_OUTSIDE_BEGIN_END(ctx);
1046
1047 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1048 if (address & 0x3) {
1049 /* addr must be multiple of four */
1050 _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
1051 return;
1052 }
1053
1054 switch (matrix) {
1055 case GL_NONE:
1056 case GL_MODELVIEW:
1057 case GL_PROJECTION:
1058 case GL_TEXTURE:
1059 case GL_COLOR:
1060 case GL_MODELVIEW_PROJECTION_NV:
1061 case GL_MATRIX0_NV:
1062 case GL_MATRIX1_NV:
1063 case GL_MATRIX2_NV:
1064 case GL_MATRIX3_NV:
1065 case GL_MATRIX4_NV:
1066 case GL_MATRIX5_NV:
1067 case GL_MATRIX6_NV:
1068 case GL_MATRIX7_NV:
1069 /* OK, fallthrough */
1070 break;
1071 default:
1072 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
1073 return;
1074 }
1075
1076 switch (transform) {
1077 case GL_IDENTITY_NV:
1078 case GL_INVERSE_NV:
1079 case GL_TRANSPOSE_NV:
1080 case GL_INVERSE_TRANSPOSE_NV:
1081 /* OK, fallthrough */
1082 break;
1083 default:
1084 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
1085 return;
1086 }
1087
1088 ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
1089 ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
1090 }
1091 else {
1092 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
1093 return;
1094 }
1095 }
1096
1097
1098 void
1099 _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
1100 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1101 {
1102 struct program *prog;
1103 struct fragment_program *fragProg;
1104 GLint i;
1105 GET_CURRENT_CONTEXT(ctx);
1106 ASSERT_OUTSIDE_BEGIN_END(ctx);
1107
1108 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1109 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1110 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
1111 return;
1112 }
1113
1114 if (len <= 0) {
1115 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1116 return;
1117 }
1118
1119 fragProg = (struct fragment_program *) prog;
1120 for (i = 0; i < fragProg->NumParameters; i++) {
1121 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1122 (const char *) name, len) &&
1123 fragProg->Parameters[i].Name[len] == 0) {
1124 ASSERT(!fragProg->Parameters[i].Constant);
1125 fragProg->Parameters[i].Values[0] = x;
1126 fragProg->Parameters[i].Values[1] = y;
1127 fragProg->Parameters[i].Values[2] = z;
1128 fragProg->Parameters[i].Values[3] = w;
1129 return;
1130 }
1131 }
1132
1133 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1134 }
1135
1136
1137 void
1138 _mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
1139 const float v[])
1140 {
1141 _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
1142 }
1143
1144
1145 void
1146 _mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
1147 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
1148 {
1149 _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
1150 (GLfloat)z, (GLfloat)w);
1151 }
1152
1153
1154 void
1155 _mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
1156 const double v[])
1157 {
1158 _mesa_ProgramNamedParameter4fNV(id, len, name,
1159 (GLfloat)v[0], (GLfloat)v[1],
1160 (GLfloat)v[2], (GLfloat)v[3]);
1161 }
1162
1163
1164 void
1165 _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
1166 GLfloat *params)
1167 {
1168 struct program *prog;
1169 struct fragment_program *fragProg;
1170 GLint i;
1171 GET_CURRENT_CONTEXT(ctx);
1172
1173 if (!ctx->_CurrentProgram)
1174 ASSERT_OUTSIDE_BEGIN_END(ctx);
1175
1176 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1177 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1178 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
1179 return;
1180 }
1181
1182 if (len <= 0) {
1183 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1184 return;
1185 }
1186
1187 fragProg = (struct fragment_program *) prog;
1188 for (i = 0; i < fragProg->NumParameters; i++) {
1189 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1190 (const char *) name, len) &&
1191 fragProg->Parameters[i].Name[len] == 0) {
1192 ASSERT(!fragProg->Parameters[i].Constant);
1193 params[0] = fragProg->Parameters[i].Values[0];
1194 params[1] = fragProg->Parameters[i].Values[1];
1195 params[2] = fragProg->Parameters[i].Values[2];
1196 params[3] = fragProg->Parameters[i].Values[3];
1197 return;
1198 }
1199 }
1200
1201 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1202 }
1203
1204
1205 void
1206 _mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
1207 GLdouble *params)
1208 {
1209 GLfloat floatParams[4];
1210 _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
1211 COPY_4V(params, floatParams);
1212 }