Silence compiler warnings about implicit casts or conversions by supplying explicit...
[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.Inputs[VERT_ATTRIB_POS], 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 COPY_4V(params, ctx->VertexProgram.Parameters[index]);
508 }
509 else {
510 _mesa_error(ctx, GL_INVALID_VALUE,
511 "glGetProgramParameterfvNV(index)");
512 return;
513 }
514 }
515 else {
516 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
517 return;
518 }
519 }
520 else {
521 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
522 return;
523 }
524 }
525
526
527 /**
528 * Get a program parameter register.
529 * \note Not compiled into display lists.
530 * \note Called from the GL API dispatcher.
531 */
532 void
533 _mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
534 GLenum pname, GLdouble *params)
535 {
536 GET_CURRENT_CONTEXT(ctx);
537 ASSERT_OUTSIDE_BEGIN_END(ctx);
538
539 if (target == GL_VERTEX_PROGRAM_NV) {
540 if (pname == GL_PROGRAM_PARAMETER_NV) {
541 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
542 COPY_4V(params, ctx->VertexProgram.Parameters[index]);
543 }
544 else {
545 _mesa_error(ctx, GL_INVALID_VALUE,
546 "glGetProgramParameterdvNV(index)");
547 return;
548 }
549 }
550 else {
551 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
552 return;
553 }
554 }
555 else {
556 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
557 return;
558 }
559 }
560
561
562 /**
563 * Get a program attribute.
564 * \note Not compiled into display lists.
565 * \note Called from the GL API dispatcher.
566 */
567 void
568 _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
569 {
570 struct program *prog;
571 GET_CURRENT_CONTEXT(ctx);
572
573 if (!ctx->_CurrentProgram)
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
610 if (!ctx->_CurrentProgram)
611 ASSERT_OUTSIDE_BEGIN_END(ctx);
612
613 if (pname != GL_PROGRAM_STRING_NV) {
614 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
615 return;
616 }
617
618 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
619 if (!prog) {
620 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
621 return;
622 }
623
624 if (prog->String) {
625 MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
626 }
627 else {
628 program[0] = 0;
629 }
630 }
631
632
633 /**
634 * Get matrix tracking information.
635 * \note Not compiled into display lists.
636 * \note Called from the GL API dispatcher.
637 */
638 void
639 _mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
640 GLenum pname, GLint *params)
641 {
642 GET_CURRENT_CONTEXT(ctx);
643 ASSERT_OUTSIDE_BEGIN_END(ctx);
644
645 if (target == GL_VERTEX_PROGRAM_NV
646 && ctx->Extensions.NV_vertex_program) {
647 GLuint i;
648
649 if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
650 _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
651 return;
652 }
653
654 i = address / 4;
655
656 switch (pname) {
657 case GL_TRACK_MATRIX_NV:
658 params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
659 return;
660 case GL_TRACK_MATRIX_TRANSFORM_NV:
661 params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
662 return;
663 default:
664 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
665 return;
666 }
667 }
668 else {
669 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
670 return;
671 }
672 }
673
674
675 /**
676 * Get a vertex (or vertex array) attribute.
677 * \note Not compiled into display lists.
678 * \note Called from the GL API dispatcher.
679 */
680 void
681 _mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
682 {
683 GET_CURRENT_CONTEXT(ctx);
684 ASSERT_OUTSIDE_BEGIN_END(ctx);
685
686 if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
687 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
688 return;
689 }
690
691 switch (pname) {
692 case GL_ATTRIB_ARRAY_SIZE_NV:
693 params[0] = ctx->Array.VertexAttrib[index].Size;
694 break;
695 case GL_ATTRIB_ARRAY_STRIDE_NV:
696 params[0] = ctx->Array.VertexAttrib[index].Stride;
697 break;
698 case GL_ATTRIB_ARRAY_TYPE_NV:
699 params[0] = ctx->Array.VertexAttrib[index].Type;
700 break;
701 case GL_CURRENT_ATTRIB_NV:
702 FLUSH_CURRENT(ctx, 0);
703 COPY_4V(params, ctx->Current.Attrib[index]);
704 break;
705 default:
706 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
707 return;
708 }
709 }
710
711 /**
712 * Get a vertex (or vertex array) attribute.
713 * \note Not compiled into display lists.
714 * \note Called from the GL API dispatcher.
715 */
716 void
717 _mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
718 {
719 GET_CURRENT_CONTEXT(ctx);
720 ASSERT_OUTSIDE_BEGIN_END(ctx);
721
722 if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
723 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
724 return;
725 }
726
727 switch (pname) {
728 case GL_ATTRIB_ARRAY_SIZE_NV:
729 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
730 break;
731 case GL_ATTRIB_ARRAY_STRIDE_NV:
732 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
733 break;
734 case GL_ATTRIB_ARRAY_TYPE_NV:
735 params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
736 break;
737 case GL_CURRENT_ATTRIB_NV:
738 FLUSH_CURRENT(ctx, 0);
739 COPY_4V(params, ctx->Current.Attrib[index]);
740 break;
741 default:
742 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
743 return;
744 }
745 }
746
747 /**
748 * Get a vertex (or vertex array) attribute.
749 * \note Not compiled into display lists.
750 * \note Called from the GL API dispatcher.
751 */
752 void
753 _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
754 {
755 GET_CURRENT_CONTEXT(ctx);
756 ASSERT_OUTSIDE_BEGIN_END(ctx);
757
758 if (index == 0 || index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
759 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
760 return;
761 }
762
763 switch (pname) {
764 case GL_ATTRIB_ARRAY_SIZE_NV:
765 params[0] = ctx->Array.VertexAttrib[index].Size;
766 break;
767 case GL_ATTRIB_ARRAY_STRIDE_NV:
768 params[0] = ctx->Array.VertexAttrib[index].Stride;
769 break;
770 case GL_ATTRIB_ARRAY_TYPE_NV:
771 params[0] = ctx->Array.VertexAttrib[index].Type;
772 break;
773 case GL_CURRENT_ATTRIB_NV:
774 FLUSH_CURRENT(ctx, 0);
775 params[0] = (GLint) ctx->Current.Attrib[index][0];
776 params[1] = (GLint) ctx->Current.Attrib[index][1];
777 params[2] = (GLint) ctx->Current.Attrib[index][2];
778 params[3] = (GLint) ctx->Current.Attrib[index][3];
779 break;
780 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
781 if (!ctx->Extensions.ARB_vertex_buffer_object) {
782 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
783 return;
784 }
785 params[0] = ctx->Array.VertexAttribArrayBufferBinding[index];
786 break;
787 default:
788 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
789 return;
790 }
791 }
792
793
794 /**
795 * Get a vertex array attribute pointer.
796 * \note Not compiled into display lists.
797 * \note Called from the GL API dispatcher.
798 */
799 void
800 _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
801 {
802 GET_CURRENT_CONTEXT(ctx);
803 ASSERT_OUTSIDE_BEGIN_END(ctx);
804
805 if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
806 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
807 return;
808 }
809
810 if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
811 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
812 return;
813 }
814
815 *pointer = ctx->Array.VertexAttrib[index].Ptr;;
816 }
817
818
819 /**
820 * Determine if id names a program.
821 * \note Not compiled into display lists.
822 * \note Called from both glIsProgramNV and glIsProgramARB.
823 * \param id is the program identifier
824 * \return GL_TRUE if id is a program, else GL_FALSE.
825 */
826 GLboolean
827 _mesa_IsProgramNV(GLuint id)
828 {
829 struct program *prog;
830 GET_CURRENT_CONTEXT(ctx);
831 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
832
833 if (id == 0)
834 return GL_FALSE;
835
836 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
837 if (prog && prog->Target)
838 return GL_TRUE;
839 else
840 return GL_FALSE;
841 }
842
843
844 /**
845 * Load/parse/compile a program.
846 * \note Called from the GL API dispatcher.
847 */
848 void
849 _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
850 const GLubyte *program)
851 {
852 struct program *prog;
853 GET_CURRENT_CONTEXT(ctx);
854 ASSERT_OUTSIDE_BEGIN_END(ctx);
855
856 if (id == 0) {
857 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
858 return;
859 }
860
861 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
862
863 if (prog && prog->Target != 0 && prog->Target != target) {
864 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
865 return;
866 }
867
868 if ((target == GL_VERTEX_PROGRAM_NV ||
869 target == GL_VERTEX_STATE_PROGRAM_NV)
870 && ctx->Extensions.NV_vertex_program) {
871 struct vertex_program *vprog = (struct vertex_program *) prog;
872 if (!vprog) {
873 vprog = CALLOC_STRUCT(vertex_program);
874 if (!vprog) {
875 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
876 return;
877 }
878 vprog->Base.RefCount = 1;
879 vprog->Base.Resident = GL_TRUE;
880 _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
881 }
882 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
883 }
884 else if (target == GL_FRAGMENT_PROGRAM_NV
885 && ctx->Extensions.NV_fragment_program) {
886 struct fragment_program *fprog = (struct fragment_program *) prog;
887 if (!fprog) {
888 fprog = CALLOC_STRUCT(fragment_program);
889 if (!fprog) {
890 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
891 return;
892 }
893 fprog->Base.RefCount = 1;
894 fprog->Base.Resident = GL_TRUE;
895 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
896 }
897 _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
898 }
899 else {
900 _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
901 }
902 }
903
904
905
906 /**
907 * Set a program parameter register.
908 * \note Called from the GL API dispatcher.
909 */
910 void
911 _mesa_ProgramParameter4dNV(GLenum target, GLuint index,
912 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
913 {
914 _mesa_ProgramParameter4fNV(target, index,
915 (GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
916 }
917
918
919 /**
920 * Set a program parameter register.
921 * \note Called from the GL API dispatcher.
922 */
923 void
924 _mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
925 const GLdouble *params)
926 {
927 _mesa_ProgramParameter4fNV(target, index,
928 (GLfloat)params[0], (GLfloat)params[1],
929 (GLfloat)params[2], (GLfloat)params[3]);
930 }
931
932
933 /**
934 * Set a program parameter register.
935 * \note Called from the GL API dispatcher.
936 */
937 void
938 _mesa_ProgramParameter4fNV(GLenum target, GLuint index,
939 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
940 {
941 GET_CURRENT_CONTEXT(ctx);
942 ASSERT_OUTSIDE_BEGIN_END(ctx);
943
944 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
945 if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
946 ASSIGN_4V(ctx->VertexProgram.Parameters[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 for (i = 0; i < num; i++) {
992 ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0];
993 ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1];
994 ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2];
995 ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3];
996 params += 4;
997 };
998 }
999 else {
1000 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
1001 return;
1002 }
1003 }
1004
1005
1006 /**
1007 * Set a sequence of program parameter registers.
1008 * \note Called from the GL API dispatcher.
1009 */
1010 void
1011 _mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
1012 GLuint num, const GLfloat *params)
1013 {
1014 GET_CURRENT_CONTEXT(ctx);
1015 ASSERT_OUTSIDE_BEGIN_END(ctx);
1016
1017 if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
1018 GLuint i;
1019 if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
1020 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
1021 return;
1022 }
1023 for (i = 0; i < num; i++) {
1024 COPY_4V(ctx->VertexProgram.Parameters[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 GLuint 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 GLuint 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 }