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