nvprogram.c revision 726a04a2cd1bf159a6c40584b4b2b9bc5948a82e
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5.2
4 *
5 * Copyright (C) 1999-2006  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 * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40#include "main/glheader.h"
41#include "main/context.h"
42#include "main/hash.h"
43#include "main/imports.h"
44#include "main/macros.h"
45#include "program.h"
46#include "prog_parameter.h"
47#include "prog_instruction.h"
48#include "nvfragparse.h"
49#include "nvvertparse.h"
50#include "nvprogram.h"
51
52
53
54/**
55 * Execute a vertex state program.
56 * \note Called from the GL API dispatcher.
57 */
58void GLAPIENTRY
59_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
60{
61   struct gl_vertex_program *vprog;
62   GET_CURRENT_CONTEXT(ctx);
63   ASSERT_OUTSIDE_BEGIN_END(ctx);
64
65   if (target != GL_VERTEX_STATE_PROGRAM_NV) {
66      _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV");
67      return;
68   }
69
70   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
71
72   vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id);
73
74   if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
75      _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
76      return;
77   }
78
79   _mesa_problem(ctx, "glExecuteProgramNV() not supported");
80}
81
82
83/**
84 * Determine if a set of programs is resident in hardware.
85 * \note Not compiled into display lists.
86 * \note Called from the GL API dispatcher.
87 */
88GLboolean GLAPIENTRY
89_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
90                            GLboolean *residences)
91{
92   GLint i, j;
93   GLboolean allResident = GL_TRUE;
94   GET_CURRENT_CONTEXT(ctx);
95   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
96
97   if (n < 0) {
98      _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
99      return GL_FALSE;
100   }
101
102   for (i = 0; i < n; i++) {
103      const struct gl_program *prog;
104      if (ids[i] == 0) {
105         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
106         return GL_FALSE;
107      }
108      prog = _mesa_lookup_program(ctx, ids[i]);
109      if (!prog) {
110         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
111         return GL_FALSE;
112      }
113      if (prog->Resident) {
114	 if (!allResident)
115	    residences[i] = GL_TRUE;
116      }
117      else {
118         if (allResident) {
119	    allResident = GL_FALSE;
120	    for (j = 0; j < i; j++)
121	       residences[j] = GL_TRUE;
122	 }
123	 residences[i] = GL_FALSE;
124      }
125   }
126
127   return allResident;
128}
129
130
131/**
132 * Request that a set of programs be resident in hardware.
133 * \note Called from the GL API dispatcher.
134 */
135void GLAPIENTRY
136_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
137{
138   GLint i;
139   GET_CURRENT_CONTEXT(ctx);
140   ASSERT_OUTSIDE_BEGIN_END(ctx);
141
142   if (n < 0) {
143      _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
144      return;
145   }
146
147   /* just error checking for now */
148   for (i = 0; i < n; i++) {
149      struct gl_program *prog;
150
151      if (ids[i] == 0) {
152         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
153         return;
154      }
155
156      prog = _mesa_lookup_program(ctx, ids[i]);
157      if (!prog) {
158         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
159         return;
160      }
161
162      /* XXX this is really a hardware thing we should hook out */
163      prog->Resident = GL_TRUE;
164   }
165}
166
167
168/**
169 * Get a program parameter register.
170 * \note Not compiled into display lists.
171 * \note Called from the GL API dispatcher.
172 */
173void GLAPIENTRY
174_mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
175                              GLenum pname, GLfloat *params)
176{
177   GET_CURRENT_CONTEXT(ctx);
178   ASSERT_OUTSIDE_BEGIN_END(ctx);
179
180   if (target == GL_VERTEX_PROGRAM_NV) {
181      if (pname == GL_PROGRAM_PARAMETER_NV) {
182         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
183            COPY_4V(params, ctx->VertexProgram.Parameters[index]);
184         }
185         else {
186            _mesa_error(ctx, GL_INVALID_VALUE,
187                        "glGetProgramParameterfvNV(index)");
188            return;
189         }
190      }
191      else {
192         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
193         return;
194      }
195   }
196   else {
197      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
198      return;
199   }
200}
201
202
203/**
204 * Get a program parameter register.
205 * \note Not compiled into display lists.
206 * \note Called from the GL API dispatcher.
207 */
208void GLAPIENTRY
209_mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
210                              GLenum pname, GLdouble *params)
211{
212   GET_CURRENT_CONTEXT(ctx);
213   ASSERT_OUTSIDE_BEGIN_END(ctx);
214
215   if (target == GL_VERTEX_PROGRAM_NV) {
216      if (pname == GL_PROGRAM_PARAMETER_NV) {
217         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
218            COPY_4V(params, ctx->VertexProgram.Parameters[index]);
219         }
220         else {
221            _mesa_error(ctx, GL_INVALID_VALUE,
222                        "glGetProgramParameterdvNV(index)");
223            return;
224         }
225      }
226      else {
227         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
228         return;
229      }
230   }
231   else {
232      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
233      return;
234   }
235}
236
237
238/**
239 * Get a program attribute.
240 * \note Not compiled into display lists.
241 * \note Called from the GL API dispatcher.
242 */
243void GLAPIENTRY
244_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
245{
246   struct gl_program *prog;
247   GET_CURRENT_CONTEXT(ctx);
248
249   ASSERT_OUTSIDE_BEGIN_END(ctx);
250
251   prog = _mesa_lookup_program(ctx, id);
252   if (!prog) {
253      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
254      return;
255   }
256
257   switch (pname) {
258      case GL_PROGRAM_TARGET_NV:
259         *params = prog->Target;
260         return;
261      case GL_PROGRAM_LENGTH_NV:
262         *params = prog->String ?(GLint)_mesa_strlen((char *) prog->String) : 0;
263         return;
264      case GL_PROGRAM_RESIDENT_NV:
265         *params = prog->Resident;
266         return;
267      default:
268         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
269         return;
270   }
271}
272
273
274/**
275 * Get the program source code.
276 * \note Not compiled into display lists.
277 * \note Called from the GL API dispatcher.
278 */
279void GLAPIENTRY
280_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
281{
282   struct gl_program *prog;
283   GET_CURRENT_CONTEXT(ctx);
284
285   ASSERT_OUTSIDE_BEGIN_END(ctx);
286
287   if (pname != GL_PROGRAM_STRING_NV) {
288      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
289      return;
290   }
291
292   prog = _mesa_lookup_program(ctx, id);
293   if (!prog) {
294      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
295      return;
296   }
297
298   if (prog->String) {
299      MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String));
300   }
301   else {
302      program[0] = 0;
303   }
304}
305
306
307/**
308 * Get matrix tracking information.
309 * \note Not compiled into display lists.
310 * \note Called from the GL API dispatcher.
311 */
312void GLAPIENTRY
313_mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
314                         GLenum pname, GLint *params)
315{
316   GET_CURRENT_CONTEXT(ctx);
317   ASSERT_OUTSIDE_BEGIN_END(ctx);
318
319   if (target == GL_VERTEX_PROGRAM_NV
320       && ctx->Extensions.NV_vertex_program) {
321      GLuint i;
322
323      if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
324         _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
325         return;
326      }
327
328      i = address / 4;
329
330      switch (pname) {
331         case GL_TRACK_MATRIX_NV:
332            params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
333            return;
334         case GL_TRACK_MATRIX_TRANSFORM_NV:
335            params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
336            return;
337         default:
338            _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
339            return;
340      }
341   }
342   else {
343      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
344      return;
345   }
346}
347
348
349/**
350 * Get a vertex (or vertex array) attribute.
351 * \note Not compiled into display lists.
352 * \note Called from the GL API dispatcher.
353 */
354void GLAPIENTRY
355_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
356{
357   const struct gl_client_array *array;
358   GET_CURRENT_CONTEXT(ctx);
359   ASSERT_OUTSIDE_BEGIN_END(ctx);
360
361   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
362      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
363      return;
364   }
365
366   array = &ctx->Array.ArrayObj->VertexAttrib[index];
367
368   switch (pname) {
369      case GL_ATTRIB_ARRAY_SIZE_NV:
370         params[0] = array->Size;
371         break;
372      case GL_ATTRIB_ARRAY_STRIDE_NV:
373         params[0] = array->Stride;
374         break;
375      case GL_ATTRIB_ARRAY_TYPE_NV:
376         params[0] = array->Type;
377         break;
378      case GL_CURRENT_ATTRIB_NV:
379         if (index == 0) {
380            _mesa_error(ctx, GL_INVALID_OPERATION,
381                        "glGetVertexAttribdvNV(index == 0)");
382            return;
383         }
384	 FLUSH_CURRENT(ctx, 0);
385         COPY_4V(params, ctx->Current.Attrib[index]);
386         break;
387      default:
388         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
389         return;
390   }
391}
392
393/**
394 * Get a vertex (or vertex array) attribute.
395 * \note Not compiled into display lists.
396 * \note Called from the GL API dispatcher.
397 */
398void GLAPIENTRY
399_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
400{
401   const struct gl_client_array *array;
402   GET_CURRENT_CONTEXT(ctx);
403   ASSERT_OUTSIDE_BEGIN_END(ctx);
404
405   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
406      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
407      return;
408   }
409
410   array = &ctx->Array.ArrayObj->VertexAttrib[index];
411
412   switch (pname) {
413      case GL_ATTRIB_ARRAY_SIZE_NV:
414         params[0] = (GLfloat) array->Size;
415         break;
416      case GL_ATTRIB_ARRAY_STRIDE_NV:
417         params[0] = (GLfloat) array->Stride;
418         break;
419      case GL_ATTRIB_ARRAY_TYPE_NV:
420         params[0] = (GLfloat) array->Type;
421         break;
422      case GL_CURRENT_ATTRIB_NV:
423         if (index == 0) {
424            _mesa_error(ctx, GL_INVALID_OPERATION,
425                        "glGetVertexAttribfvNV(index == 0)");
426            return;
427         }
428	 FLUSH_CURRENT(ctx, 0);
429         COPY_4V(params, ctx->Current.Attrib[index]);
430         break;
431      default:
432         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
433         return;
434   }
435}
436
437/**
438 * Get a vertex (or vertex array) attribute.
439 * \note Not compiled into display lists.
440 * \note Called from the GL API dispatcher.
441 */
442void GLAPIENTRY
443_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
444{
445   const struct gl_client_array *array;
446   GET_CURRENT_CONTEXT(ctx);
447   ASSERT_OUTSIDE_BEGIN_END(ctx);
448
449   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
450      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
451      return;
452   }
453
454   array = &ctx->Array.ArrayObj->VertexAttrib[index];
455
456   switch (pname) {
457      case GL_ATTRIB_ARRAY_SIZE_NV:
458         params[0] = array->Size;
459         break;
460      case GL_ATTRIB_ARRAY_STRIDE_NV:
461         params[0] = array->Stride;
462         break;
463      case GL_ATTRIB_ARRAY_TYPE_NV:
464         params[0] = array->Type;
465         break;
466      case GL_CURRENT_ATTRIB_NV:
467         if (index == 0) {
468            _mesa_error(ctx, GL_INVALID_OPERATION,
469                        "glGetVertexAttribivNV(index == 0)");
470            return;
471         }
472	 FLUSH_CURRENT(ctx, 0);
473         params[0] = (GLint) ctx->Current.Attrib[index][0];
474         params[1] = (GLint) ctx->Current.Attrib[index][1];
475         params[2] = (GLint) ctx->Current.Attrib[index][2];
476         params[3] = (GLint) ctx->Current.Attrib[index][3];
477         break;
478      case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
479         params[0] = array->BufferObj->Name;
480         break;
481      default:
482         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
483         return;
484   }
485}
486
487
488/**
489 * Get a vertex array attribute pointer.
490 * \note Not compiled into display lists.
491 * \note Called from the GL API dispatcher.
492 */
493void GLAPIENTRY
494_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
495{
496   GET_CURRENT_CONTEXT(ctx);
497   ASSERT_OUTSIDE_BEGIN_END(ctx);
498
499   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
500      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
501      return;
502   }
503
504   if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
505      _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
506      return;
507   }
508
509   *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
510}
511
512void
513_mesa_emit_nv_temp_initialization(GLcontext *ctx,
514				  struct gl_program *program)
515{
516   struct prog_instruction *inst;
517   int i;
518
519   if (!ctx->Shader.EmitNVTempInitialization)
520      return;
521
522   /* We'll swizzle up a zero temporary so we can use it for the
523    * ARL.
524    */
525   if (program->NumTemporaries == 0)
526      program->NumTemporaries = 1;
527
528   _mesa_insert_instructions(program, 0, program->NumTemporaries + 1);
529
530   for (i = 0; i < program->NumTemporaries; i++) {
531      struct prog_instruction *inst = &program->Instructions[i];
532
533      inst->Opcode = OPCODE_SWZ;
534      inst->DstReg.File = PROGRAM_TEMPORARY;
535      inst->DstReg.Index = i;
536      inst->DstReg.WriteMask = WRITEMASK_XYZW;
537      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
538      inst->SrcReg[0].Index = 0;
539      inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO,
540					      SWIZZLE_ZERO,
541					      SWIZZLE_ZERO,
542					      SWIZZLE_ZERO);
543   }
544
545   inst = &program->Instructions[i];
546   inst->Opcode = OPCODE_ARL;
547   inst->DstReg.File = PROGRAM_ADDRESS;
548   inst->DstReg.Index = 0;
549   inst->DstReg.WriteMask = WRITEMASK_XYZW;
550   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
551   inst->SrcReg[0].Index = 0;
552   inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
553
554   if (program->NumAddressRegs == 0)
555      program->NumAddressRegs = 1;
556}
557
558void
559_mesa_setup_nv_temporary_count(GLcontext *ctx, struct gl_program *program)
560{
561   int i;
562
563   program->NumTemporaries = 0;
564   for (i = 0; i < program->NumInstructions; i++) {
565      struct prog_instruction *inst = &program->Instructions[i];
566
567      if (inst->DstReg.File == PROGRAM_TEMPORARY) {
568	 program->NumTemporaries = MAX2(program->NumTemporaries,
569					inst->DstReg.Index + 1);
570      }
571      if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) {
572	 program->NumTemporaries = MAX2(program->NumTemporaries,
573					inst->SrcReg[0].Index + 1);
574      }
575      if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) {
576	 program->NumTemporaries = MAX2(program->NumTemporaries,
577					inst->SrcReg[1].Index + 1);
578      }
579      if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) {
580	 program->NumTemporaries = MAX2(program->NumTemporaries,
581					inst->SrcReg[2].Index + 1);
582      }
583   }
584}
585
586/**
587 * Load/parse/compile a program.
588 * \note Called from the GL API dispatcher.
589 */
590void GLAPIENTRY
591_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
592                    const GLubyte *program)
593{
594   struct gl_program *prog;
595   GET_CURRENT_CONTEXT(ctx);
596   ASSERT_OUTSIDE_BEGIN_END(ctx);
597
598   if (id == 0) {
599      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
600      return;
601   }
602
603   if (len < 0) {
604      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)");
605      return;
606   }
607
608   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
609
610   prog = _mesa_lookup_program(ctx, id);
611
612   if (prog && prog->Target != 0 && prog->Target != target) {
613      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
614      return;
615   }
616
617   if ((target == GL_VERTEX_PROGRAM_NV ||
618        target == GL_VERTEX_STATE_PROGRAM_NV)
619       && ctx->Extensions.NV_vertex_program) {
620      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
621      if (!vprog || prog == &_mesa_DummyProgram) {
622         vprog = (struct gl_vertex_program *)
623            ctx->Driver.NewProgram(ctx, target, id);
624         if (!vprog) {
625            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
626            return;
627         }
628         _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
629      }
630      _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
631   }
632   else if (target == GL_FRAGMENT_PROGRAM_NV
633            && ctx->Extensions.NV_fragment_program) {
634      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
635      if (!fprog || prog == &_mesa_DummyProgram) {
636         fprog = (struct gl_fragment_program *)
637            ctx->Driver.NewProgram(ctx, target, id);
638         if (!fprog) {
639            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
640            return;
641         }
642         _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
643      }
644      _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
645   }
646   else {
647      _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
648   }
649}
650
651
652
653/**
654 * Set a sequence of program parameter registers.
655 * \note Called from the GL API dispatcher.
656 */
657void GLAPIENTRY
658_mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
659                             GLuint num, const GLdouble *params)
660{
661   GET_CURRENT_CONTEXT(ctx);
662   ASSERT_OUTSIDE_BEGIN_END(ctx);
663
664   if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
665      GLuint i;
666      if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
667         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
668         return;
669      }
670      for (i = 0; i < num; i++) {
671         ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0];
672         ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1];
673         ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2];
674         ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3];
675         params += 4;
676      };
677   }
678   else {
679      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
680      return;
681   }
682}
683
684
685/**
686 * Set a sequence of program parameter registers.
687 * \note Called from the GL API dispatcher.
688 */
689void GLAPIENTRY
690_mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
691                             GLuint num, const GLfloat *params)
692{
693   GET_CURRENT_CONTEXT(ctx);
694   ASSERT_OUTSIDE_BEGIN_END(ctx);
695
696   if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
697      GLuint i;
698      if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) {
699         _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
700         return;
701      }
702      for (i = 0; i < num; i++) {
703         COPY_4V(ctx->VertexProgram.Parameters[index + i], params);
704         params += 4;
705      }
706   }
707   else {
708      _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
709      return;
710   }
711}
712
713
714
715/**
716 * Setup tracking of matrices into program parameter registers.
717 * \note Called from the GL API dispatcher.
718 */
719void GLAPIENTRY
720_mesa_TrackMatrixNV(GLenum target, GLuint address,
721                    GLenum matrix, GLenum transform)
722{
723   GET_CURRENT_CONTEXT(ctx);
724   ASSERT_OUTSIDE_BEGIN_END(ctx);
725
726   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
727
728   if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) {
729      if (address & 0x3) {
730         /* addr must be multiple of four */
731         _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
732         return;
733      }
734
735      switch (matrix) {
736         case GL_NONE:
737         case GL_MODELVIEW:
738         case GL_PROJECTION:
739         case GL_TEXTURE:
740         case GL_COLOR:
741         case GL_MODELVIEW_PROJECTION_NV:
742         case GL_MATRIX0_NV:
743         case GL_MATRIX1_NV:
744         case GL_MATRIX2_NV:
745         case GL_MATRIX3_NV:
746         case GL_MATRIX4_NV:
747         case GL_MATRIX5_NV:
748         case GL_MATRIX6_NV:
749         case GL_MATRIX7_NV:
750            /* OK, fallthrough */
751            break;
752         default:
753            _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
754            return;
755      }
756
757      switch (transform) {
758         case GL_IDENTITY_NV:
759         case GL_INVERSE_NV:
760         case GL_TRANSPOSE_NV:
761         case GL_INVERSE_TRANSPOSE_NV:
762            /* OK, fallthrough */
763            break;
764         default:
765            _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
766            return;
767      }
768
769      ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
770      ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
771   }
772   else {
773      _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
774      return;
775   }
776}
777
778
779void GLAPIENTRY
780_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
781                                GLfloat x, GLfloat y, GLfloat z, GLfloat w)
782{
783   struct gl_program *prog;
784   struct gl_fragment_program *fragProg;
785   GLfloat *v;
786
787   GET_CURRENT_CONTEXT(ctx);
788   ASSERT_OUTSIDE_BEGIN_END(ctx);
789
790   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
791
792   prog = _mesa_lookup_program(ctx, id);
793   if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
794      _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
795      return;
796   }
797
798   if (len <= 0) {
799      _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)");
800      return;
801   }
802
803   fragProg = (struct gl_fragment_program *) prog;
804   v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len,
805                                    (char *) name);
806   if (v) {
807      v[0] = x;
808      v[1] = y;
809      v[2] = z;
810      v[3] = w;
811      return;
812   }
813
814   _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)");
815}
816
817
818void GLAPIENTRY
819_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
820                                 const float v[])
821{
822   _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
823}
824
825
826void GLAPIENTRY
827_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
828                                GLdouble x, GLdouble y, GLdouble z, GLdouble w)
829{
830   _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
831                                   (GLfloat)z, (GLfloat)w);
832}
833
834
835void GLAPIENTRY
836_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
837                                 const double v[])
838{
839   _mesa_ProgramNamedParameter4fNV(id, len, name,
840                                   (GLfloat)v[0], (GLfloat)v[1],
841                                   (GLfloat)v[2], (GLfloat)v[3]);
842}
843
844
845void GLAPIENTRY
846_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
847                                   GLfloat *params)
848{
849   struct gl_program *prog;
850   struct gl_fragment_program *fragProg;
851   const GLfloat *v;
852
853   GET_CURRENT_CONTEXT(ctx);
854
855   ASSERT_OUTSIDE_BEGIN_END(ctx);
856
857   prog = _mesa_lookup_program(ctx, id);
858   if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
859      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
860      return;
861   }
862
863   if (len <= 0) {
864      _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
865      return;
866   }
867
868   fragProg = (struct gl_fragment_program *) prog;
869   v = _mesa_lookup_parameter_value(fragProg->Base.Parameters,
870                                    len, (char *) name);
871   if (v) {
872      params[0] = v[0];
873      params[1] = v[1];
874      params[2] = v[2];
875      params[3] = v[3];
876      return;
877   }
878
879   _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
880}
881
882
883void GLAPIENTRY
884_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
885                                   GLdouble *params)
886{
887   GLfloat floatParams[4];
888   _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
889   COPY_4V(params, floatParams);
890}
891