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  */
60 void GLAPIENTRY
_mesa_ExecuteProgramNV(GLenum target,GLuint id,const GLfloat * params)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  */
90 GLboolean GLAPIENTRY
_mesa_AreProgramsResidentNV(GLsizei n,const GLuint * ids,GLboolean * residences)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  */
137 void GLAPIENTRY
_mesa_RequestResidentProgramsNV(GLsizei n,const GLuint * ids)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  */
175 void GLAPIENTRY
_mesa_GetProgramParameterfvNV(GLenum target,GLuint index,GLenum pname,GLfloat * params)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  */
210 void GLAPIENTRY
_mesa_GetProgramParameterdvNV(GLenum target,GLuint index,GLenum pname,GLdouble * params)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  */
245 void GLAPIENTRY
_mesa_GetProgramivNV(GLuint id,GLenum pname,GLint * params)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  */
281 void GLAPIENTRY
_mesa_GetProgramStringNV(GLuint id,GLenum pname,GLubyte * program)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  */
314 void GLAPIENTRY
_mesa_GetTrackMatrixivNV(GLenum target,GLuint address,GLenum pname,GLint * params)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  */
356 void GLAPIENTRY
_mesa_GetVertexAttribdvNV(GLuint index,GLenum pname,GLdouble * params)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  */
400 void GLAPIENTRY
_mesa_GetVertexAttribfvNV(GLuint index,GLenum pname,GLfloat * params)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  */
444 void GLAPIENTRY
_mesa_GetVertexAttribivNV(GLuint index,GLenum pname,GLint * params)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  */
495 void GLAPIENTRY
_mesa_GetVertexAttribPointervNV(GLuint index,GLenum pname,GLvoid ** pointer)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 
514 void
_mesa_emit_nv_temp_initialization(struct gl_context * ctx,struct gl_program * program)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 
562 void
_mesa_setup_nv_temporary_count(struct gl_program * program)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  */
594 void GLAPIENTRY
_mesa_LoadProgramNV(GLenum target,GLuint id,GLsizei len,const GLubyte * program)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  */
684 void GLAPIENTRY
_mesa_ProgramParameters4dvNV(GLenum target,GLuint index,GLsizei num,const GLdouble * params)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  */
716 void GLAPIENTRY
_mesa_ProgramParameters4fvNV(GLenum target,GLuint index,GLsizei num,const GLfloat * params)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  */
746 void GLAPIENTRY
_mesa_TrackMatrixNV(GLenum target,GLuint address,GLenum matrix,GLenum transform)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 
806 void GLAPIENTRY
_mesa_ProgramNamedParameter4fNV(GLuint id,GLsizei len,const GLubyte * name,GLfloat x,GLfloat y,GLfloat z,GLfloat w)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 
845 void GLAPIENTRY
_mesa_ProgramNamedParameter4fvNV(GLuint id,GLsizei len,const GLubyte * name,const float v[])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 
853 void GLAPIENTRY
_mesa_ProgramNamedParameter4dNV(GLuint id,GLsizei len,const GLubyte * name,GLdouble x,GLdouble y,GLdouble z,GLdouble w)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 
862 void GLAPIENTRY
_mesa_ProgramNamedParameter4dvNV(GLuint id,GLsizei len,const GLubyte * name,const double v[])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 
872 void GLAPIENTRY
_mesa_GetProgramNamedParameterfvNV(GLuint id,GLsizei len,const GLubyte * name,GLfloat * params)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 
910 void GLAPIENTRY
_mesa_GetProgramNamedParameterdvNV(GLuint id,GLsizei len,const GLubyte * name,GLdouble * params)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