Merge Jose's documentation and core Mesa changes from embedded branch
[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 ASSERT_OUTSIDE_BEGIN_END(ctx);
575
576 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
577 if (!prog) {
578 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
579 return;
580 }
581
582 switch (pname) {
583 case GL_PROGRAM_TARGET_NV:
584 *params = prog->Target;
585 return;
586 case GL_PROGRAM_LENGTH_NV:
587 *params = prog->String ? _mesa_strlen((char *) prog->String) : 0;
588 return;
589 case GL_PROGRAM_RESIDENT_NV:
590 *params = prog->Resident;
591 return;
592 default:
593 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
594 return;
595 }
596 }
597
598
599 /**
600 * Get the program source code.
601 * \note Not compiled into display lists.
602 * \note Called from the GL API dispatcher.
603 */
604 void
605 _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
606 {
607 struct program *prog;
608 GET_CURRENT_CONTEXT(ctx);
609 ASSERT_OUTSIDE_BEGIN_END(ctx);
610
611 if (pname != GL_PROGRAM_STRING_NV) {
612 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
613 return;
614 }
615
616 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
617 if (!prog) {
618 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
619 return;
620 }
621
622 if (prog->String) {
623 MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
624 }
625 else {
626 program[0] = 0;
627 }
628 }
629
630
631 /**
632 * Get matrix tracking information.
633 * \note Not compiled into display lists.
634 * \note Called from the GL API dispatcher.
635 */
636 void
637 _mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
638 GLenum pname, GLint *params)
639 {
640 GET_CURRENT_CONTEXT(ctx);
641 ASSERT_OUTSIDE_BEGIN_END(ctx);
642
643 if (target == GL_VERTEX_PROGRAM_NV
644 && ctx->Extensions.NV_vertex_program) {
645 GLuint i;
646
647 if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
648 _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
649 return;
650 }
651
652 i = address / 4;
653
654 switch (pname) {
655 case GL_TRACK_MATRIX_NV:
656 params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
657 return;
658 case GL_TRACK_MATRIX_TRANSFORM_NV:
659 params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
660 return;
661 default:
662 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
663 return;
664 }
665 }
666 else {
667 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
668 return;
669 }
670 }
671
672
673 /**
674 * Get a vertex (or vertex array) attribute.
675 * \note Not compiled into display lists.
676 * \note Called from the GL API dispatcher.
677 */
678 void
679 _mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
680 {
681 GET_CURRENT_CONTEXT(ctx);
682 ASSERT_OUTSIDE_BEGIN_END(ctx);
683
684 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
685 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
686 return;
687 }
688
689 switch (pname) {
690 case GL_ATTRIB_ARRAY_SIZE_NV:
691 params[0] = ctx->Array.VertexAttrib[index].Size;
692 break;
693 case GL_ATTRIB_ARRAY_STRIDE_NV:
694 params[0] = ctx->Array.VertexAttrib[index].Stride;
695 break;
696 case GL_ATTRIB_ARRAY_TYPE_NV:
697 params[0] = ctx->Array.VertexAttrib[index].Type;
698 break;
699 case GL_CURRENT_ATTRIB_NV:
700 FLUSH_CURRENT(ctx, 0);
701 COPY_4V(params, ctx->Current.Attrib[index]);
702 break;
703 default:
704 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
705 return;
706 }
707 }
708
709 /**
710 * Get a vertex (or vertex array) attribute.
711 * \note Not compiled into display lists.
712 * \note Called from the GL API dispatcher.
713 */
714 void
715 _mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
716 {
717 GET_CURRENT_CONTEXT(ctx);
718 ASSERT_OUTSIDE_BEGIN_END(ctx);
719
720 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
721 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
722 return;
723 }
724
725 switch (pname) {
726 case GL_ATTRIB_ARRAY_SIZE_NV:
727 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
728 break;
729 case GL_ATTRIB_ARRAY_STRIDE_NV:
730 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
731 break;
732 case GL_ATTRIB_ARRAY_TYPE_NV:
733 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
734 break;
735 case GL_CURRENT_ATTRIB_NV:
736 FLUSH_CURRENT(ctx, 0);
737 COPY_4V(params, ctx->Current.Attrib[index]);
738 break;
739 default:
740 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
741 return;
742 }
743 }
744
745 /**
746 * Get a vertex (or vertex array) attribute.
747 * \note Not compiled into display lists.
748 * \note Called from the GL API dispatcher.
749 */
750 void
751 _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
752 {
753 GET_CURRENT_CONTEXT(ctx);
754 ASSERT_OUTSIDE_BEGIN_END(ctx);
755
756 if (index == 0 || index >= VP_NUM_INPUT_REGS) {
757 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
758 return;
759 }
760
761 switch (pname) {
762 case GL_ATTRIB_ARRAY_SIZE_NV:
763 params[0] = ctx->Array.VertexAttrib[index].Size;
764 break;
765 case GL_ATTRIB_ARRAY_STRIDE_NV:
766 params[0] = ctx->Array.VertexAttrib[index].Stride;
767 break;
768 case GL_ATTRIB_ARRAY_TYPE_NV:
769 params[0] = ctx->Array.VertexAttrib[index].Type;
770 break;
771 case GL_CURRENT_ATTRIB_NV:
772 FLUSH_CURRENT(ctx, 0);
773 COPY_4V_CAST(params, ctx->Current.Attrib[index], GLint);
774 break;
775 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
776 if (!ctx->Extensions.ARB_vertex_buffer_object) {
777 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
778 return;
779 }
780 params[0] = ctx->Array.VertexAttribArrayBufferBinding[index];
781 break;
782 default:
783 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
784 return;
785 }
786 }
787
788
789 /**
790 * Get a vertex array attribute pointer.
791 * \note Not compiled into display lists.
792 * \note Called from the GL API dispatcher.
793 */
794 void
795 _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
796 {
797 GET_CURRENT_CONTEXT(ctx);
798 ASSERT_OUTSIDE_BEGIN_END(ctx);
799
800 if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
801 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
802 return;
803 }
804
805 if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
806 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
807 return;
808 }
809
810 *pointer = ctx->Array.VertexAttrib[index].Ptr;;
811 }
812
813
814 /**
815 * Determine if id names a program.
816 * \note Not compiled into display lists.
817 * \note Called from both glIsProgramNV and glIsProgramARB.
818 * \param id is the program identifier
819 * \return GL_TRUE if id is a program, else GL_FALSE.
820 */
821 GLboolean
822 _mesa_IsProgramNV(GLuint id)
823 {
824 struct program *prog;
825 GET_CURRENT_CONTEXT(ctx);
826 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
827
828 if (id == 0)
829 return GL_FALSE;
830
831 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
832 if (prog && prog->Target)
833 return GL_TRUE;
834 else
835 return GL_FALSE;
836 }
837
838
839 /**
840 * Load/parse/compile a program.
841 * \note Called from the GL API dispatcher.
842 */
843 void
844 _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
845 const GLubyte *program)
846 {
847 struct program *prog;
848 GET_CURRENT_CONTEXT(ctx);
849 ASSERT_OUTSIDE_BEGIN_END(ctx);
850
851 if (id == 0) {
852 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
853 return;
854 }
855
856 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
857
858 if (prog && prog->Target != 0 && prog->Target != target) {
859 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
860 return;
861 }
862
863 if ((target == GL_VERTEX_PROGRAM_NV ||
864 target == GL_VERTEX_STATE_PROGRAM_NV)
865 && ctx->Extensions.NV_vertex_program) {
866 struct vertex_program *vprog = (struct vertex_program *) prog;
867 if (!vprog) {
868 vprog = CALLOC_STRUCT(vertex_program);
869 if (!vprog) {
870 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
871 return;
872 }
873 vprog->Base.RefCount = 1;
874 vprog->Base.Resident = GL_TRUE;
875 _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
876 }
877 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
878 }
879 else if (target == GL_FRAGMENT_PROGRAM_NV
880 && ctx->Extensions.NV_fragment_program) {
881 struct fragment_program *fprog = (struct fragment_program *) prog;
882 if (!fprog) {
883 fprog = CALLOC_STRUCT(fragment_program);
884 if (!fprog) {
885 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
886 return;
887 }
888 fprog->Base.RefCount = 1;
889 fprog->Base.Resident = GL_TRUE;
890 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
891 }
892 _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
893 }
894 else {
895 _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
896 }
897 }
898
899
900
901 /**
902 * Set a program parameter register.
903 * \note Called from the GL API dispatcher.
904 */
905 void
906 _mesa_ProgramParameter4dNV(GLenum target, GLuint index,
907 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
908 {
909 _mesa_ProgramParameter4fNV(target, index,
910 (GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
911 }
912
913
914 /**
915 * Set a program parameter register.
916 * \note Called from the GL API dispatcher.
917 */
918 void
919 _mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
920 const GLdouble *params)
921 {
922 _mesa_ProgramParameter4fNV(target, index,
923 (GLfloat)params[0], (GLfloat)params[1],
924 (GLfloat)params[2], (GLfloat)params[3]);
925 }
926
927
928 /**
929 * Set a program parameter register.
930 * \note Called from the GL API dispatcher.
931 */
932 void
933 _mesa_ProgramParameter4fNV(GLenum target, GLuint index,
934 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
935 {
936 GET_CURRENT_CONTEXT(ctx);
937 ASSERT_OUTSIDE_BEGIN_END(ctx);
938
939 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
940 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
941 index += VP_PROG_REG_START;
942 ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
943 }
944 else {
945 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameterNV(index)");
946 return;
947 }
948 }
949 else {
950 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameterNV");
951 return;
952 }
953 }
954
955
956 /**
957 * Set a program parameter register.
958 * \note Called from the GL API dispatcher.
959 */
960 void
961 _mesa_ProgramParameter4fvNV(GLenum target, GLuint index,
962 const GLfloat *params)
963 {
964 _mesa_ProgramParameter4fNV(target, index,
965 params[0], params[1], params[2], params[3]);
966 }
967
968
969
970 /**
971 * Set a sequence of program parameter registers.
972 * \note Called from the GL API dispatcher.
973 */
974 void
975 _mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
976 GLuint num, const GLdouble *params)
977 {
978 GET_CURRENT_CONTEXT(ctx);
979 ASSERT_OUTSIDE_BEGIN_END(ctx);
980
981 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
982 GLuint i;
983 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
984 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
985 return;
986 }
987 index += VP_PROG_REG_START;
988 for (i = 0; i < num; i++) {
989 COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index + i],
990 params, GLfloat);
991 params += 4;
992 };
993 }
994 else {
995 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
996 return;
997 }
998 }
999
1000
1001 /**
1002 * Set a sequence of program parameter registers.
1003 * \note Called from the GL API dispatcher.
1004 */
1005 void
1006 _mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
1007 GLuint num, const GLfloat *params)
1008 {
1009 GET_CURRENT_CONTEXT(ctx);
1010 ASSERT_OUTSIDE_BEGIN_END(ctx);
1011
1012 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1013 GLuint i;
1014 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
1015 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
1016 return;
1017 }
1018 index += VP_PROG_REG_START;
1019 for (i = 0; i < num; i++) {
1020 COPY_4V(ctx->VertexProgram.Machine.Registers[index + i], params);
1021 params += 4;
1022 };
1023 }
1024 else {
1025 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
1026 return;
1027 }
1028 }
1029
1030
1031
1032 /**
1033 * Setup tracking of matrices into program parameter registers.
1034 * \note Called from the GL API dispatcher.
1035 */
1036 void
1037 _mesa_TrackMatrixNV(GLenum target, GLuint address,
1038 GLenum matrix, GLenum transform)
1039 {
1040 GET_CURRENT_CONTEXT(ctx);
1041 ASSERT_OUTSIDE_BEGIN_END(ctx);
1042
1043 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1044 if (address & 0x3) {
1045 /* addr must be multiple of four */
1046 _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
1047 return;
1048 }
1049
1050 switch (matrix) {
1051 case GL_NONE:
1052 case GL_MODELVIEW:
1053 case GL_PROJECTION:
1054 case GL_TEXTURE:
1055 case GL_COLOR:
1056 case GL_MODELVIEW_PROJECTION_NV:
1057 case GL_MATRIX0_NV:
1058 case GL_MATRIX1_NV:
1059 case GL_MATRIX2_NV:
1060 case GL_MATRIX3_NV:
1061 case GL_MATRIX4_NV:
1062 case GL_MATRIX5_NV:
1063 case GL_MATRIX6_NV:
1064 case GL_MATRIX7_NV:
1065 /* OK, fallthrough */
1066 break;
1067 default:
1068 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
1069 return;
1070 }
1071
1072 switch (transform) {
1073 case GL_IDENTITY_NV:
1074 case GL_INVERSE_NV:
1075 case GL_TRANSPOSE_NV:
1076 case GL_INVERSE_TRANSPOSE_NV:
1077 /* OK, fallthrough */
1078 break;
1079 default:
1080 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
1081 return;
1082 }
1083
1084 ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
1085 ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
1086 }
1087 else {
1088 _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
1089 return;
1090 }
1091 }
1092
1093
1094 void
1095 _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
1096 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1097 {
1098 struct program *prog;
1099 struct fragment_program *fragProg;
1100 GLint i;
1101 GET_CURRENT_CONTEXT(ctx);
1102 ASSERT_OUTSIDE_BEGIN_END(ctx);
1103
1104 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1105 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1106 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
1107 return;
1108 }
1109
1110 if (len <= 0) {
1111 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1112 return;
1113 }
1114
1115 fragProg = (struct fragment_program *) prog;
1116 for (i = 0; i < fragProg->NumParameters; i++) {
1117 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1118 (const char *) name, len) &&
1119 fragProg->Parameters[i].Name[len] == 0) {
1120 ASSERT(!fragProg->Parameters[i].Constant);
1121 fragProg->Parameters[i].Values[0] = x;
1122 fragProg->Parameters[i].Values[1] = y;
1123 fragProg->Parameters[i].Values[2] = z;
1124 fragProg->Parameters[i].Values[3] = w;
1125 return;
1126 }
1127 }
1128
1129 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV");
1130 }
1131
1132
1133 void
1134 _mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
1135 const float v[])
1136 {
1137 _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
1138 }
1139
1140
1141 void
1142 _mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
1143 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
1144 {
1145 _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
1146 (GLfloat)z, (GLfloat)w);
1147 }
1148
1149
1150 void
1151 _mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
1152 const double v[])
1153 {
1154 _mesa_ProgramNamedParameter4fNV(id, len, name,
1155 (GLfloat)v[0], (GLfloat)v[1],
1156 (GLfloat)v[2], (GLfloat)v[3]);
1157 }
1158
1159
1160 void
1161 _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
1162 GLfloat *params)
1163 {
1164 struct program *prog;
1165 struct fragment_program *fragProg;
1166 GLint i;
1167 GET_CURRENT_CONTEXT(ctx);
1168 ASSERT_OUTSIDE_BEGIN_END(ctx);
1169
1170 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
1171 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
1172 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
1173 return;
1174 }
1175
1176 if (len <= 0) {
1177 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1178 return;
1179 }
1180
1181 fragProg = (struct fragment_program *) prog;
1182 for (i = 0; i < fragProg->NumParameters; i++) {
1183 if (!_mesa_strncmp(fragProg->Parameters[i].Name,
1184 (const char *) name, len) &&
1185 fragProg->Parameters[i].Name[len] == 0) {
1186 ASSERT(!fragProg->Parameters[i].Constant);
1187 params[0] = fragProg->Parameters[i].Values[0];
1188 params[1] = fragProg->Parameters[i].Values[1];
1189 params[2] = fragProg->Parameters[i].Values[2];
1190 params[3] = fragProg->Parameters[i].Values[3];
1191 return;
1192 }
1193 }
1194
1195 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
1196 }
1197
1198
1199 void
1200 _mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
1201 GLdouble *params)
1202 {
1203 GLfloat floatParams[4];
1204 _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
1205 COPY_4V(params, floatParams);
1206 }
1207
1208
1209 #if 000
1210 void
1211 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
1212 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1213 {
1214 GET_CURRENT_CONTEXT(ctx);
1215 ASSERT_OUTSIDE_BEGIN_END(ctx);
1216
1217 if (target == GL_FRAGMENT_PROGRAM_NV) {
1218 struct fragment_program *fprog = ctx->FragmentProgram.Current;
1219 if (!fprog) {
1220 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
1221 return;
1222 }
1223 if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
1224 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
1225 return;
1226 }
1227 fprog->Base.LocalParams[index][0] = x;
1228 fprog->Base.LocalParams[index][1] = y;
1229 fprog->Base.LocalParams[index][2] = z;
1230 fprog->Base.LocalParams[index][3] = w;
1231 }
1232 else {
1233 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
1234 return;
1235 }
1236 }
1237
1238
1239 /* XXX move into arbprogram.c */
1240 void
1241 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
1242 const GLfloat *params)
1243 {
1244 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
1245 params[2], params[3]);
1246 }
1247
1248
1249 /* XXX move into arbprogram.c */
1250 void
1251 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
1252 GLdouble x, GLdouble y,
1253 GLdouble z, GLdouble w)
1254 {
1255 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat)x, (GLfloat)y,
1256 (GLfloat)z, (GLfloat)w);
1257 }
1258
1259
1260 /* XXX move into arbprogram.c */
1261 void
1262 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
1263 const GLdouble *params)
1264 {
1265 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat)params[0],
1266 (GLfloat)params[1], (GLfloat)params[2],
1267 (GLfloat)params[3]);
1268 }
1269
1270
1271 /* XXX move into arbprogram.c */
1272 void
1273 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
1274 GLfloat *params)
1275 {
1276 GET_CURRENT_CONTEXT(ctx);
1277 ASSERT_OUTSIDE_BEGIN_END(ctx);
1278
1279 if (target == GL_FRAGMENT_PROGRAM_NV) {
1280 struct fragment_program *fprog = ctx->FragmentProgram.Current;
1281 if (!fprog) {
1282 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
1283 return;
1284 }
1285 if (index >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) {
1286 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramLocalParameterARB");
1287 return;
1288 }
1289 params[0] = fprog->Base.LocalParams[index][0];
1290 params[1] = fprog->Base.LocalParams[index][1];
1291 params[2] = fprog->Base.LocalParams[index][2];
1292 params[3] = fprog->Base.LocalParams[index][3];
1293 }
1294 else {
1295 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramLocalParameterARB");
1296 return;
1297 }
1298 }
1299
1300
1301 /* XXX move into arbprogram.c */
1302 void
1303 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
1304 GLdouble *params)
1305 {
1306 GLfloat floatParams[4];
1307 _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
1308 COPY_4V(params, floatParams);
1309 }
1310 #endif