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