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 "main/mtypes.h"
46#include "main/nvprogram.h"
47#include "program/arbprogparse.h"
48#include "program/nvfragparse.h"
49#include "program/nvvertparse.h"
50#include "program/program.h"
51#include "program/prog_instruction.h"
52#include "program/prog_parameter.h"
53
54
55
56/**
57 * Execute a vertex state program.
58 * \note Called from the GL API dispatcher.
59 */
60void GLAPIENTRY
61_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
62{
63   struct gl_vertex_program *vprog;
64   GET_CURRENT_CONTEXT(ctx);
65   ASSERT_OUTSIDE_BEGIN_END(ctx);
66
67   if (target != GL_VERTEX_STATE_PROGRAM_NV) {
68      _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV");
69      return;
70   }
71
72   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
73
74   vprog = gl_vertex_program(_mesa_lookup_program(ctx, id));
75
76   if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) {
77      _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
78      return;
79   }
80
81   _mesa_problem(ctx, "glExecuteProgramNV() not supported");
82}
83
84
85/**
86 * Determine if a set of programs is resident in hardware.
87 * \note Not compiled into display lists.
88 * \note Called from the GL API dispatcher.
89 */
90GLboolean GLAPIENTRY
91_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
92                            GLboolean *residences)
93{
94   GLint i, j;
95   GLboolean allResident = GL_TRUE;
96   GET_CURRENT_CONTEXT(ctx);
97   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
98
99   if (n < 0) {
100      _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
101      return GL_FALSE;
102   }
103
104   for (i = 0; i < n; i++) {
105      const struct gl_program *prog;
106      if (ids[i] == 0) {
107         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
108         return GL_FALSE;
109      }
110      prog = _mesa_lookup_program(ctx, ids[i]);
111      if (!prog) {
112         _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
113         return GL_FALSE;
114      }
115      if (prog->Resident) {
116	 if (!allResident)
117	    residences[i] = GL_TRUE;
118      }
119      else {
120         if (allResident) {
121	    allResident = GL_FALSE;
122	    for (j = 0; j < i; j++)
123	       residences[j] = GL_TRUE;
124	 }
125	 residences[i] = GL_FALSE;
126      }
127   }
128
129   return allResident;
130}
131
132
133/**
134 * Request that a set of programs be resident in hardware.
135 * \note Called from the GL API dispatcher.
136 */
137void GLAPIENTRY
138_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
139{
140   GLint i;
141   GET_CURRENT_CONTEXT(ctx);
142   ASSERT_OUTSIDE_BEGIN_END(ctx);
143
144   if (n < 0) {
145      _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
146      return;
147   }
148
149   /* just error checking for now */
150   for (i = 0; i < n; i++) {
151      struct gl_program *prog;
152
153      if (ids[i] == 0) {
154         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
155         return;
156      }
157
158      prog = _mesa_lookup_program(ctx, ids[i]);
159      if (!prog) {
160         _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
161         return;
162      }
163
164      /* XXX this is really a hardware thing we should hook out */
165      prog->Resident = GL_TRUE;
166   }
167}
168
169
170/**
171 * Get a program parameter register.
172 * \note Not compiled into display lists.
173 * \note Called from the GL API dispatcher.
174 */
175void GLAPIENTRY
176_mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
177                              GLenum pname, GLfloat *params)
178{
179   GET_CURRENT_CONTEXT(ctx);
180   ASSERT_OUTSIDE_BEGIN_END(ctx);
181
182   if (target == GL_VERTEX_PROGRAM_NV) {
183      if (pname == GL_PROGRAM_PARAMETER_NV) {
184         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
185            COPY_4V(params, ctx->VertexProgram.Parameters[index]);
186         }
187         else {
188            _mesa_error(ctx, GL_INVALID_VALUE,
189                        "glGetProgramParameterfvNV(index)");
190            return;
191         }
192      }
193      else {
194         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)");
195         return;
196      }
197   }
198   else {
199      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)");
200      return;
201   }
202}
203
204
205/**
206 * Get a program parameter register.
207 * \note Not compiled into display lists.
208 * \note Called from the GL API dispatcher.
209 */
210void GLAPIENTRY
211_mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
212                              GLenum pname, GLdouble *params)
213{
214   GET_CURRENT_CONTEXT(ctx);
215   ASSERT_OUTSIDE_BEGIN_END(ctx);
216
217   if (target == GL_VERTEX_PROGRAM_NV) {
218      if (pname == GL_PROGRAM_PARAMETER_NV) {
219         if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) {
220            COPY_4V(params, ctx->VertexProgram.Parameters[index]);
221         }
222         else {
223            _mesa_error(ctx, GL_INVALID_VALUE,
224                        "glGetProgramParameterdvNV(index)");
225            return;
226         }
227      }
228      else {
229         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)");
230         return;
231      }
232   }
233   else {
234      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)");
235      return;
236   }
237}
238
239
240/**
241 * Get a program attribute.
242 * \note Not compiled into display lists.
243 * \note Called from the GL API dispatcher.
244 */
245void GLAPIENTRY
246_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
247{
248   struct gl_program *prog;
249   GET_CURRENT_CONTEXT(ctx);
250
251   ASSERT_OUTSIDE_BEGIN_END(ctx);
252
253   prog = _mesa_lookup_program(ctx, id);
254   if (!prog) {
255      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
256      return;
257   }
258
259   switch (pname) {
260      case GL_PROGRAM_TARGET_NV:
261         *params = prog->Target;
262         return;
263      case GL_PROGRAM_LENGTH_NV:
264         *params = prog->String ?(GLint) strlen((char *) prog->String) : 0;
265         return;
266      case GL_PROGRAM_RESIDENT_NV:
267         *params = prog->Resident;
268         return;
269      default:
270         _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
271         return;
272   }
273}
274
275
276/**
277 * Get the program source code.
278 * \note Not compiled into display lists.
279 * \note Called from the GL API dispatcher.
280 */
281void GLAPIENTRY
282_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
283{
284   struct gl_program *prog;
285   GET_CURRENT_CONTEXT(ctx);
286
287   ASSERT_OUTSIDE_BEGIN_END(ctx);
288
289   if (pname != GL_PROGRAM_STRING_NV) {
290      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
291      return;
292   }
293
294   prog = _mesa_lookup_program(ctx, id);
295   if (!prog) {
296      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
297      return;
298   }
299
300   if (prog->String) {
301      memcpy(program, prog->String, strlen((char *) prog->String));
302   }
303   else {
304      program[0] = 0;
305   }
306}
307
308
309/**
310 * Get matrix tracking information.
311 * \note Not compiled into display lists.
312 * \note Called from the GL API dispatcher.
313 */
314void GLAPIENTRY
315_mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
316                         GLenum pname, GLint *params)
317{
318   GET_CURRENT_CONTEXT(ctx);
319   ASSERT_OUTSIDE_BEGIN_END(ctx);
320
321   if (target == GL_VERTEX_PROGRAM_NV
322       && ctx->Extensions.NV_vertex_program) {
323      GLuint i;
324
325      if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) {
326         _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
327         return;
328      }
329
330      i = address / 4;
331
332      switch (pname) {
333         case GL_TRACK_MATRIX_NV:
334            params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
335            return;
336         case GL_TRACK_MATRIX_TRANSFORM_NV:
337            params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
338            return;
339         default:
340            _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
341            return;
342      }
343   }
344   else {
345      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
346      return;
347   }
348}
349
350
351/**
352 * Get a vertex (or vertex array) attribute.
353 * \note Not compiled into display lists.
354 * \note Called from the GL API dispatcher.
355 */
356void GLAPIENTRY
357_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
358{
359   const struct gl_client_array *array;
360   GET_CURRENT_CONTEXT(ctx);
361   ASSERT_OUTSIDE_BEGIN_END(ctx);
362
363   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
364      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
365      return;
366   }
367
368   array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)];
369
370   switch (pname) {
371      case GL_ATTRIB_ARRAY_SIZE_NV:
372         params[0] = array->Size;
373         break;
374      case GL_ATTRIB_ARRAY_STRIDE_NV:
375         params[0] = array->Stride;
376         break;
377      case GL_ATTRIB_ARRAY_TYPE_NV:
378         params[0] = array->Type;
379         break;
380      case GL_CURRENT_ATTRIB_NV:
381         if (index == 0) {
382            _mesa_error(ctx, GL_INVALID_OPERATION,
383                        "glGetVertexAttribdvNV(index == 0)");
384            return;
385         }
386	 FLUSH_CURRENT(ctx, 0);
387         COPY_4V(params, ctx->Current.Attrib[index]);
388         break;
389      default:
390         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
391         return;
392   }
393}
394
395/**
396 * Get a vertex (or vertex array) attribute.
397 * \note Not compiled into display lists.
398 * \note Called from the GL API dispatcher.
399 */
400void GLAPIENTRY
401_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
402{
403   const struct gl_client_array *array;
404   GET_CURRENT_CONTEXT(ctx);
405   ASSERT_OUTSIDE_BEGIN_END(ctx);
406
407   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
408      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
409      return;
410   }
411
412   array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)];
413
414   switch (pname) {
415      case GL_ATTRIB_ARRAY_SIZE_NV:
416         params[0] = (GLfloat) array->Size;
417         break;
418      case GL_ATTRIB_ARRAY_STRIDE_NV:
419         params[0] = (GLfloat) array->Stride;
420         break;
421      case GL_ATTRIB_ARRAY_TYPE_NV:
422         params[0] = (GLfloat) array->Type;
423         break;
424      case GL_CURRENT_ATTRIB_NV:
425         if (index == 0) {
426            _mesa_error(ctx, GL_INVALID_OPERATION,
427                        "glGetVertexAttribfvNV(index == 0)");
428            return;
429         }
430	 FLUSH_CURRENT(ctx, 0);
431         COPY_4V(params, ctx->Current.Attrib[index]);
432         break;
433      default:
434         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
435         return;
436   }
437}
438
439/**
440 * Get a vertex (or vertex array) attribute.
441 * \note Not compiled into display lists.
442 * \note Called from the GL API dispatcher.
443 */
444void GLAPIENTRY
445_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
446{
447   const struct gl_client_array *array;
448   GET_CURRENT_CONTEXT(ctx);
449   ASSERT_OUTSIDE_BEGIN_END(ctx);
450
451   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
452      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
453      return;
454   }
455
456   array = &ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)];
457
458   switch (pname) {
459      case GL_ATTRIB_ARRAY_SIZE_NV:
460         params[0] = array->Size;
461         break;
462      case GL_ATTRIB_ARRAY_STRIDE_NV:
463         params[0] = array->Stride;
464         break;
465      case GL_ATTRIB_ARRAY_TYPE_NV:
466         params[0] = array->Type;
467         break;
468      case GL_CURRENT_ATTRIB_NV:
469         if (index == 0) {
470            _mesa_error(ctx, GL_INVALID_OPERATION,
471                        "glGetVertexAttribivNV(index == 0)");
472            return;
473         }
474	 FLUSH_CURRENT(ctx, 0);
475         params[0] = (GLint) ctx->Current.Attrib[index][0];
476         params[1] = (GLint) ctx->Current.Attrib[index][1];
477         params[2] = (GLint) ctx->Current.Attrib[index][2];
478         params[3] = (GLint) ctx->Current.Attrib[index][3];
479         break;
480      case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
481         params[0] = array->BufferObj->Name;
482         break;
483      default:
484         _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
485         return;
486   }
487}
488
489
490/**
491 * Get a vertex array attribute pointer.
492 * \note Not compiled into display lists.
493 * \note Called from the GL API dispatcher.
494 */
495void GLAPIENTRY
496_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
497{
498   GET_CURRENT_CONTEXT(ctx);
499   ASSERT_OUTSIDE_BEGIN_END(ctx);
500
501   if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
502      _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
503      return;
504   }
505
506   if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
507      _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
508      return;
509   }
510
511   *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
512}
513
514void
515_mesa_emit_nv_temp_initialization(struct gl_context *ctx,
516				  struct gl_program *program)
517{
518   struct prog_instruction *inst;
519   GLuint i;
520   struct gl_shader_compiler_options* options =
521         &ctx->ShaderCompilerOptions[_mesa_program_target_to_index(program->Target)];
522
523   if (!options->EmitNVTempInitialization)
524      return;
525
526   /* We'll swizzle up a zero temporary so we can use it for the
527    * ARL.
528    */
529   if (program->NumTemporaries == 0)
530      program->NumTemporaries = 1;
531
532   _mesa_insert_instructions(program, 0, program->NumTemporaries + 1);
533
534   for (i = 0; i < program->NumTemporaries; i++) {
535      struct prog_instruction *inst = &program->Instructions[i];
536
537      inst->Opcode = OPCODE_SWZ;
538      inst->DstReg.File = PROGRAM_TEMPORARY;
539      inst->DstReg.Index = i;
540      inst->DstReg.WriteMask = WRITEMASK_XYZW;
541      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
542      inst->SrcReg[0].Index = 0;
543      inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO,
544					      SWIZZLE_ZERO,
545					      SWIZZLE_ZERO,
546					      SWIZZLE_ZERO);
547   }
548
549   inst = &program->Instructions[i];
550   inst->Opcode = OPCODE_ARL;
551   inst->DstReg.File = PROGRAM_ADDRESS;
552   inst->DstReg.Index = 0;
553   inst->DstReg.WriteMask = WRITEMASK_XYZW;
554   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
555   inst->SrcReg[0].Index = 0;
556   inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
557
558   if (program->NumAddressRegs == 0)
559      program->NumAddressRegs = 1;
560}
561
562void
563_mesa_setup_nv_temporary_count(struct gl_program *program)
564{
565   GLuint i;
566
567   program->NumTemporaries = 0;
568   for (i = 0; i < program->NumInstructions; i++) {
569      struct prog_instruction *inst = &program->Instructions[i];
570
571      if (inst->DstReg.File == PROGRAM_TEMPORARY) {
572	 program->NumTemporaries = MAX2(program->NumTemporaries,
573					inst->DstReg.Index + 1);
574      }
575      if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) {
576	 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
577					inst->SrcReg[0].Index + 1);
578      }
579      if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) {
580	 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
581					inst->SrcReg[1].Index + 1);
582      }
583      if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) {
584	 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
585					inst->SrcReg[2].Index + 1);
586      }
587   }
588}
589
590/**
591 * Load/parse/compile a program.
592 * \note Called from the GL API dispatcher.
593 */
594void GLAPIENTRY
595_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
596                    const GLubyte *program)
597{
598   struct gl_program *prog;
599   GET_CURRENT_CONTEXT(ctx);
600   ASSERT_OUTSIDE_BEGIN_END(ctx);
601
602   if (!ctx->Extensions.NV_vertex_program
603       && !ctx->Extensions.NV_fragment_program) {
604      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()");
605      return;
606   }
607
608   if (id == 0) {
609      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
610      return;
611   }
612
613   if (len < 0) {
614      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)");
615      return;
616   }
617
618   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
619
620   prog = _mesa_lookup_program(ctx, id);
621
622   if (prog && prog->Target != 0 && prog->Target != target) {
623      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
624      return;
625   }
626
627   if ((target == GL_VERTEX_PROGRAM_NV ||
628        target == GL_VERTEX_STATE_PROGRAM_NV)
629       && ctx->Extensions.NV_vertex_program) {
630      struct gl_vertex_program *vprog = gl_vertex_program(prog);
631      if (!vprog || prog == &_mesa_DummyProgram) {
632         vprog = gl_vertex_program(ctx->Driver.NewProgram(ctx, target, id));
633         if (!vprog) {
634            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
635            return;
636         }
637         _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
638      }
639
640      if (ctx->Extensions.ARB_vertex_program
641	  && (strncmp((char *) program, "!!ARB", 5) == 0)) {
642	 _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog);
643      } else {
644	 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
645      }
646   }
647   else if (target == GL_FRAGMENT_PROGRAM_NV
648            && ctx->Extensions.NV_fragment_program) {
649      struct gl_fragment_program *fprog = gl_fragment_program(prog);
650      if (!fprog || prog == &_mesa_DummyProgram) {
651         fprog = gl_fragment_program(ctx->Driver.NewProgram(ctx, target, id));
652         if (!fprog) {
653            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
654            return;
655         }
656         _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
657      }
658      _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
659   }
660   else if (target == GL_FRAGMENT_PROGRAM_ARB
661            && ctx->Extensions.ARB_fragment_program) {
662      struct gl_fragment_program *fprog = gl_fragment_program(prog);
663      if (!fprog || prog == &_mesa_DummyProgram) {
664         fprog = gl_fragment_program(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                             GLsizei 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      GLint 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                             GLsizei 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      GLint 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   gl_constant_value *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 = gl_fragment_program(prog);
831   v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len,
832                                    (char *) name);
833   if (v) {
834      v[0].f = x;
835      v[1].f = y;
836      v[2].f = z;
837      v[3].f = 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 gl_constant_value *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 = 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].f;
900      params[1] = v[1].f;
901      params[2] = v[2].f;
902      params[3] = v[3].f;
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