1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.0
4  *
5  * Copyright (C) 1999-2007  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 arbprogram.c
27  * ARB_vertex/fragment_program state management functions.
28  * \author Brian Paul
29  */
30 
31 
32 #include "main/glheader.h"
33 #include "main/context.h"
34 #include "main/hash.h"
35 #include "main/imports.h"
36 #include "main/macros.h"
37 #include "main/mtypes.h"
38 #include "main/arbprogram.h"
39 #include "program/arbprogparse.h"
40 #include "program/nvfragparse.h"
41 #include "program/nvvertparse.h"
42 #include "program/program.h"
43 
44 
45 
46 /**
47  * Mixing ARB and NV vertex/fragment programs can be tricky.
48  * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
49  *  but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
50  * The two different fragment program targets are supposed to be compatible
51  * to some extent (see GL_ARB_fragment_program spec).
52  * This function does the compatibility check.
53  */
54 static GLboolean
compatible_program_targets(GLenum t1,GLenum t2)55 compatible_program_targets(GLenum t1, GLenum t2)
56 {
57    if (t1 == t2)
58       return GL_TRUE;
59    if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
60       return GL_TRUE;
61    if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
62       return GL_TRUE;
63    return GL_FALSE;
64 }
65 
66 
67 /**
68  * Bind a program (make it current)
69  * \note Called from the GL API dispatcher by both glBindProgramNV
70  * and glBindProgramARB.
71  */
72 void GLAPIENTRY
_mesa_BindProgram(GLenum target,GLuint id)73 _mesa_BindProgram(GLenum target, GLuint id)
74 {
75    struct gl_program *curProg, *newProg;
76    GET_CURRENT_CONTEXT(ctx);
77    ASSERT_OUTSIDE_BEGIN_END(ctx);
78 
79    /* Error-check target and get curProg */
80    if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
81         (ctx->Extensions.NV_vertex_program ||
82          ctx->Extensions.ARB_vertex_program)) {
83       curProg = &ctx->VertexProgram.Current->Base;
84    }
85    else if ((target == GL_FRAGMENT_PROGRAM_NV
86              && ctx->Extensions.NV_fragment_program) ||
87             (target == GL_FRAGMENT_PROGRAM_ARB
88              && ctx->Extensions.ARB_fragment_program)) {
89       curProg = &ctx->FragmentProgram.Current->Base;
90    }
91    else {
92       _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
93       return;
94    }
95 
96    /*
97     * Get pointer to new program to bind.
98     * NOTE: binding to a non-existant program is not an error.
99     * That's supposed to be caught in glBegin.
100     */
101    if (id == 0) {
102       /* Bind a default program */
103       newProg = NULL;
104       if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
105          newProg = &ctx->Shared->DefaultVertexProgram->Base;
106       else
107          newProg = &ctx->Shared->DefaultFragmentProgram->Base;
108    }
109    else {
110       /* Bind a user program */
111       newProg = _mesa_lookup_program(ctx, id);
112       if (!newProg || newProg == &_mesa_DummyProgram) {
113          /* allocate a new program now */
114          newProg = ctx->Driver.NewProgram(ctx, target, id);
115          if (!newProg) {
116             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
117             return;
118          }
119          _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
120       }
121       else if (!compatible_program_targets(newProg->Target, target)) {
122          _mesa_error(ctx, GL_INVALID_OPERATION,
123                      "glBindProgramNV/ARB(target mismatch)");
124          return;
125       }
126    }
127 
128    /** All error checking is complete now **/
129 
130    if (curProg->Id == id) {
131       /* binding same program - no change */
132       return;
133    }
134 
135    /* signal new program (and its new constants) */
136    FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
137 
138    /* bind newProg */
139    if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
140       _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
141                                gl_vertex_program(newProg));
142    }
143    else if (target == GL_FRAGMENT_PROGRAM_NV ||
144             target == GL_FRAGMENT_PROGRAM_ARB) {
145       _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
146                                gl_fragment_program(newProg));
147    }
148 
149    /* Never null pointers */
150    ASSERT(ctx->VertexProgram.Current);
151    ASSERT(ctx->FragmentProgram.Current);
152 
153    if (ctx->Driver.BindProgram)
154       ctx->Driver.BindProgram(ctx, target, newProg);
155 }
156 
157 
158 /**
159  * Delete a list of programs.
160  * \note Not compiled into display lists.
161  * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
162  */
163 void GLAPIENTRY
_mesa_DeletePrograms(GLsizei n,const GLuint * ids)164 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
165 {
166    GLint i;
167    GET_CURRENT_CONTEXT(ctx);
168    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
169 
170    if (n < 0) {
171       _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
172       return;
173    }
174 
175    for (i = 0; i < n; i++) {
176       if (ids[i] != 0) {
177          struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
178          if (prog == &_mesa_DummyProgram) {
179             _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
180          }
181          else if (prog) {
182             /* Unbind program if necessary */
183             switch (prog->Target) {
184             case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
185             case GL_VERTEX_STATE_PROGRAM_NV:
186                if (ctx->VertexProgram.Current &&
187                    ctx->VertexProgram.Current->Base.Id == ids[i]) {
188                   /* unbind this currently bound program */
189                   _mesa_BindProgram(prog->Target, 0);
190                }
191                break;
192             case GL_FRAGMENT_PROGRAM_NV:
193             case GL_FRAGMENT_PROGRAM_ARB:
194                if (ctx->FragmentProgram.Current &&
195                    ctx->FragmentProgram.Current->Base.Id == ids[i]) {
196                   /* unbind this currently bound program */
197                   _mesa_BindProgram(prog->Target, 0);
198                }
199                break;
200             default:
201                _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
202                return;
203             }
204             /* The ID is immediately available for re-use now */
205             _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
206             _mesa_reference_program(ctx, &prog, NULL);
207          }
208       }
209    }
210 }
211 
212 
213 /**
214  * Generate a list of new program identifiers.
215  * \note Not compiled into display lists.
216  * \note Called by both glGenProgramsNV and glGenProgramsARB.
217  */
218 void GLAPIENTRY
_mesa_GenPrograms(GLsizei n,GLuint * ids)219 _mesa_GenPrograms(GLsizei n, GLuint *ids)
220 {
221    GLuint first;
222    GLuint i;
223    GET_CURRENT_CONTEXT(ctx);
224    ASSERT_OUTSIDE_BEGIN_END(ctx);
225 
226    if (n < 0) {
227       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
228       return;
229    }
230 
231    if (!ids)
232       return;
233 
234    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
235 
236    /* Insert pointer to dummy program as placeholder */
237    for (i = 0; i < (GLuint) n; i++) {
238       _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
239    }
240 
241    /* Return the program names */
242    for (i = 0; i < (GLuint) n; i++) {
243       ids[i] = first + i;
244    }
245 }
246 
247 
248 /**
249  * Determine if id names a vertex or fragment program.
250  * \note Not compiled into display lists.
251  * \note Called from both glIsProgramNV and glIsProgramARB.
252  * \param id is the program identifier
253  * \return GL_TRUE if id is a program, else GL_FALSE.
254  */
255 GLboolean GLAPIENTRY
_mesa_IsProgramARB(GLuint id)256 _mesa_IsProgramARB(GLuint id)
257 {
258    struct gl_program *prog = NULL;
259    GET_CURRENT_CONTEXT(ctx);
260    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
261 
262    if (id == 0)
263       return GL_FALSE;
264 
265    prog = _mesa_lookup_program(ctx, id);
266    if (prog && (prog != &_mesa_DummyProgram))
267       return GL_TRUE;
268    else
269       return GL_FALSE;
270 }
271 
272 static GLboolean
get_local_param_pointer(struct gl_context * ctx,const char * func,GLenum target,GLuint index,GLfloat ** param)273 get_local_param_pointer(struct gl_context *ctx, const char *func,
274 			GLenum target, GLuint index, GLfloat **param)
275 {
276    struct gl_program *prog;
277    GLuint maxParams;
278 
279    if (target == GL_VERTEX_PROGRAM_ARB
280        && ctx->Extensions.ARB_vertex_program) {
281       prog = &(ctx->VertexProgram.Current->Base);
282       maxParams = ctx->Const.VertexProgram.MaxLocalParams;
283    }
284    else if (target == GL_FRAGMENT_PROGRAM_ARB
285             && ctx->Extensions.ARB_fragment_program) {
286       prog = &(ctx->FragmentProgram.Current->Base);
287       maxParams = ctx->Const.FragmentProgram.MaxLocalParams;
288    }
289    else if (target == GL_FRAGMENT_PROGRAM_NV
290             && ctx->Extensions.NV_fragment_program) {
291       prog = &(ctx->FragmentProgram.Current->Base);
292       maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
293    }
294    else {
295       _mesa_error(ctx, GL_INVALID_ENUM,
296                   "%s(target)", func);
297       return GL_FALSE;
298    }
299 
300    if (index >= maxParams) {
301       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
302       return GL_FALSE;
303    }
304 
305    *param = prog->LocalParams[index];
306    return GL_TRUE;
307 }
308 
309 
310 static GLboolean
get_env_param_pointer(struct gl_context * ctx,const char * func,GLenum target,GLuint index,GLfloat ** param)311 get_env_param_pointer(struct gl_context *ctx, const char *func,
312 		      GLenum target, GLuint index, GLfloat **param)
313 {
314    if (target == GL_FRAGMENT_PROGRAM_ARB
315        && ctx->Extensions.ARB_fragment_program) {
316       if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
317          _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
318          return GL_FALSE;
319       }
320       *param = ctx->FragmentProgram.Parameters[index];
321       return GL_TRUE;
322    }
323    else if (target == GL_VERTEX_PROGRAM_ARB &&
324 	    (ctx->Extensions.ARB_vertex_program ||
325 	     ctx->Extensions.NV_vertex_program)) {
326       if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
327          _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
328          return GL_FALSE;
329       }
330       *param = ctx->VertexProgram.Parameters[index];
331       return GL_TRUE;
332    } else {
333       _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
334       return GL_FALSE;
335    }
336 }
337 
338 void GLAPIENTRY
_mesa_ProgramStringARB(GLenum target,GLenum format,GLsizei len,const GLvoid * string)339 _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
340                        const GLvoid *string)
341 {
342    struct gl_program *base;
343    GET_CURRENT_CONTEXT(ctx);
344    ASSERT_OUTSIDE_BEGIN_END(ctx);
345 
346    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
347 
348    if (!ctx->Extensions.ARB_vertex_program
349        && !ctx->Extensions.ARB_fragment_program) {
350       _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()");
351       return;
352    }
353 
354    if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
355       _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
356       return;
357    }
358 
359    /* The first couple cases are complicated.  The same enum value is used for
360     * ARB and NV vertex programs.  If the target is a vertex program, parse it
361     * using the ARB grammar if the string starts with "!!ARB" or if
362     * NV_vertex_program is not supported.
363     */
364    if (target == GL_VERTEX_PROGRAM_ARB
365        && ctx->Extensions.ARB_vertex_program
366        && ((strncmp(string, "!!ARB", 5) == 0)
367 	   || !ctx->Extensions.NV_vertex_program)) {
368       struct gl_vertex_program *prog = ctx->VertexProgram.Current;
369       _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
370 
371       base = & prog->Base;
372    }
373    else if ((target == GL_VERTEX_PROGRAM_ARB
374 	     || target == GL_VERTEX_STATE_PROGRAM_NV)
375 	    && ctx->Extensions.NV_vertex_program) {
376       struct gl_vertex_program *prog = ctx->VertexProgram.Current;
377       _mesa_parse_nv_vertex_program(ctx, target, string, len, prog);
378 
379       base = & prog->Base;
380    }
381    else if (target == GL_FRAGMENT_PROGRAM_ARB
382             && ctx->Extensions.ARB_fragment_program) {
383       struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
384       _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
385 
386       base = & prog->Base;
387    }
388    else if (target == GL_FRAGMENT_PROGRAM_NV
389             && ctx->Extensions.NV_fragment_program) {
390       struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
391       _mesa_parse_nv_fragment_program(ctx, target, string, len, prog);
392 
393       base = & prog->Base;
394    }
395    else {
396       _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
397       return;
398    }
399 
400    if (ctx->Program.ErrorPos == -1) {
401       /* finally, give the program to the driver for translation/checking */
402       if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) {
403          _mesa_error(ctx, GL_INVALID_OPERATION,
404                      "glProgramStringARB(rejected by driver");
405       }
406    }
407 }
408 
409 
410 /**
411  * Set a program env parameter register.
412  * \note Called from the GL API dispatcher.
413  * Note, this function is also used by the GL_NV_vertex_program extension
414  * (alias to ProgramParameterdNV)
415  */
416 void GLAPIENTRY
_mesa_ProgramEnvParameter4dARB(GLenum target,GLuint index,GLdouble x,GLdouble y,GLdouble z,GLdouble w)417 _mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
418                                GLdouble x, GLdouble y, GLdouble z, GLdouble w)
419 {
420    _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
421 		                  (GLfloat) z, (GLfloat) w);
422 }
423 
424 
425 /**
426  * Set a program env parameter register.
427  * \note Called from the GL API dispatcher.
428  * Note, this function is also used by the GL_NV_vertex_program extension
429  * (alias to ProgramParameterdvNV)
430  */
431 void GLAPIENTRY
_mesa_ProgramEnvParameter4dvARB(GLenum target,GLuint index,const GLdouble * params)432 _mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
433                                 const GLdouble *params)
434 {
435    _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
436 	                          (GLfloat) params[1], (GLfloat) params[2],
437 				  (GLfloat) params[3]);
438 }
439 
440 
441 /**
442  * Set a program env parameter register.
443  * \note Called from the GL API dispatcher.
444  * Note, this function is also used by the GL_NV_vertex_program extension
445  * (alias to ProgramParameterfNV)
446  */
447 void GLAPIENTRY
_mesa_ProgramEnvParameter4fARB(GLenum target,GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)448 _mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
449                                GLfloat x, GLfloat y, GLfloat z, GLfloat w)
450 {
451    GLfloat *param;
452 
453    GET_CURRENT_CONTEXT(ctx);
454    ASSERT_OUTSIDE_BEGIN_END(ctx);
455 
456    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
457 
458    if (get_env_param_pointer(ctx, "glProgramEnvParameter",
459 			     target, index, &param)) {
460       ASSIGN_4V(param, x, y, z, w);
461    }
462 }
463 
464 
465 
466 /**
467  * Set a program env parameter register.
468  * \note Called from the GL API dispatcher.
469  * Note, this function is also used by the GL_NV_vertex_program extension
470  * (alias to ProgramParameterfvNV)
471  */
472 void GLAPIENTRY
_mesa_ProgramEnvParameter4fvARB(GLenum target,GLuint index,const GLfloat * params)473 _mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
474                                 const GLfloat *params)
475 {
476    GLfloat *param;
477 
478    GET_CURRENT_CONTEXT(ctx);
479    ASSERT_OUTSIDE_BEGIN_END(ctx);
480 
481    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
482 
483    if (get_env_param_pointer(ctx, "glProgramEnvParameter4fv",
484 			      target, index, &param)) {
485       memcpy(param, params, 4 * sizeof(GLfloat));
486    }
487 }
488 
489 
490 void GLAPIENTRY
_mesa_ProgramEnvParameters4fvEXT(GLenum target,GLuint index,GLsizei count,const GLfloat * params)491 _mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
492 				 const GLfloat *params)
493 {
494    GET_CURRENT_CONTEXT(ctx);
495    GLfloat * dest;
496    ASSERT_OUTSIDE_BEGIN_END(ctx);
497 
498    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
499 
500    if (count <= 0) {
501       _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
502    }
503 
504    if (target == GL_FRAGMENT_PROGRAM_ARB
505        && ctx->Extensions.ARB_fragment_program) {
506       if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) {
507          _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
508          return;
509       }
510       dest = ctx->FragmentProgram.Parameters[index];
511    }
512    else if (target == GL_VERTEX_PROGRAM_ARB
513        && ctx->Extensions.ARB_vertex_program) {
514       if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) {
515          _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
516          return;
517       }
518       dest = ctx->VertexProgram.Parameters[index];
519    }
520    else {
521       _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
522       return;
523    }
524 
525    memcpy(dest, params, count * 4 * sizeof(GLfloat));
526 }
527 
528 
529 void GLAPIENTRY
_mesa_GetProgramEnvParameterdvARB(GLenum target,GLuint index,GLdouble * params)530 _mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
531                                   GLdouble *params)
532 {
533    GET_CURRENT_CONTEXT(ctx);
534    GLfloat *fparam;
535 
536    if (get_env_param_pointer(ctx, "glGetProgramEnvParameterdv",
537 			     target, index, &fparam)) {
538       COPY_4V(params, fparam);
539    }
540 }
541 
542 
543 void GLAPIENTRY
_mesa_GetProgramEnvParameterfvARB(GLenum target,GLuint index,GLfloat * params)544 _mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
545                                   GLfloat *params)
546 {
547    GLfloat *param;
548 
549    GET_CURRENT_CONTEXT(ctx);
550 
551    ASSERT_OUTSIDE_BEGIN_END(ctx);
552 
553    if (get_env_param_pointer(ctx, "glGetProgramEnvParameterfv",
554 			      target, index, &param)) {
555       COPY_4V(params, param);
556    }
557 }
558 
559 
560 /**
561  * Note, this function is also used by the GL_NV_fragment_program extension.
562  */
563 void GLAPIENTRY
_mesa_ProgramLocalParameter4fARB(GLenum target,GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)564 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
565                                  GLfloat x, GLfloat y, GLfloat z, GLfloat w)
566 {
567    GET_CURRENT_CONTEXT(ctx);
568    GLfloat *param;
569    ASSERT_OUTSIDE_BEGIN_END(ctx);
570 
571    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
572 
573    if (get_local_param_pointer(ctx, "glProgramLocalParameterARB",
574 			       target, index, &param)) {
575       ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
576       ASSIGN_4V(param, x, y, z, w);
577    }
578 }
579 
580 
581 /**
582  * Note, this function is also used by the GL_NV_fragment_program extension.
583  */
584 void GLAPIENTRY
_mesa_ProgramLocalParameter4fvARB(GLenum target,GLuint index,const GLfloat * params)585 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
586                                   const GLfloat *params)
587 {
588    _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
589                                     params[2], params[3]);
590 }
591 
592 
593 void GLAPIENTRY
_mesa_ProgramLocalParameters4fvEXT(GLenum target,GLuint index,GLsizei count,const GLfloat * params)594 _mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
595 				   const GLfloat *params)
596 {
597    GET_CURRENT_CONTEXT(ctx);
598    GLfloat *dest;
599    ASSERT_OUTSIDE_BEGIN_END(ctx);
600 
601    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
602 
603    if (count <= 0) {
604       _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
605    }
606 
607    if (target == GL_FRAGMENT_PROGRAM_ARB
608        && ctx->Extensions.ARB_fragment_program) {
609       if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) {
610          _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
611          return;
612       }
613       dest = ctx->FragmentProgram.Current->Base.LocalParams[index];
614    }
615    else if (target == GL_VERTEX_PROGRAM_ARB
616             && ctx->Extensions.ARB_vertex_program) {
617       if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) {
618          _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
619          return;
620       }
621       dest = ctx->VertexProgram.Current->Base.LocalParams[index];
622    }
623    else {
624       _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)");
625       return;
626    }
627 
628    memcpy(dest, params, count * 4 * sizeof(GLfloat));
629 }
630 
631 
632 /**
633  * Note, this function is also used by the GL_NV_fragment_program extension.
634  */
635 void GLAPIENTRY
_mesa_ProgramLocalParameter4dARB(GLenum target,GLuint index,GLdouble x,GLdouble y,GLdouble z,GLdouble w)636 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
637                                  GLdouble x, GLdouble y,
638                                  GLdouble z, GLdouble w)
639 {
640    _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
641                                     (GLfloat) z, (GLfloat) w);
642 }
643 
644 
645 /**
646  * Note, this function is also used by the GL_NV_fragment_program extension.
647  */
648 void GLAPIENTRY
_mesa_ProgramLocalParameter4dvARB(GLenum target,GLuint index,const GLdouble * params)649 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
650                                   const GLdouble *params)
651 {
652    _mesa_ProgramLocalParameter4fARB(target, index,
653                                     (GLfloat) params[0], (GLfloat) params[1],
654                                     (GLfloat) params[2], (GLfloat) params[3]);
655 }
656 
657 
658 /**
659  * Note, this function is also used by the GL_NV_fragment_program extension.
660  */
661 void GLAPIENTRY
_mesa_GetProgramLocalParameterfvARB(GLenum target,GLuint index,GLfloat * params)662 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
663                                     GLfloat *params)
664 {
665    GLfloat *param;
666    GET_CURRENT_CONTEXT(ctx);
667    ASSERT_OUTSIDE_BEGIN_END(ctx);
668 
669    if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
670 				target, index, &param)) {
671       COPY_4V(params, param);
672    }
673 }
674 
675 
676 /**
677  * Note, this function is also used by the GL_NV_fragment_program extension.
678  */
679 void GLAPIENTRY
_mesa_GetProgramLocalParameterdvARB(GLenum target,GLuint index,GLdouble * params)680 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
681                                     GLdouble *params)
682 {
683    GLfloat *param;
684    GET_CURRENT_CONTEXT(ctx);
685    ASSERT_OUTSIDE_BEGIN_END(ctx);
686 
687    if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
688 				target, index, &param)) {
689       COPY_4V(params, param);
690    }
691 }
692 
693 
694 void GLAPIENTRY
_mesa_GetProgramivARB(GLenum target,GLenum pname,GLint * params)695 _mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
696 {
697    const struct gl_program_constants *limits;
698    struct gl_program *prog;
699    GET_CURRENT_CONTEXT(ctx);
700 
701    ASSERT_OUTSIDE_BEGIN_END(ctx);
702 
703    if (target == GL_VERTEX_PROGRAM_ARB
704        && ctx->Extensions.ARB_vertex_program) {
705       prog = &(ctx->VertexProgram.Current->Base);
706       limits = &ctx->Const.VertexProgram;
707    }
708    else if (target == GL_FRAGMENT_PROGRAM_ARB
709             && ctx->Extensions.ARB_fragment_program) {
710       prog = &(ctx->FragmentProgram.Current->Base);
711       limits = &ctx->Const.FragmentProgram;
712    }
713    else {
714       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
715       return;
716    }
717 
718    ASSERT(prog);
719    ASSERT(limits);
720 
721    /* Queries supported for both vertex and fragment programs */
722    switch (pname) {
723       case GL_PROGRAM_LENGTH_ARB:
724          *params
725             = prog->String ? (GLint) strlen((char *) prog->String) : 0;
726          return;
727       case GL_PROGRAM_FORMAT_ARB:
728          *params = prog->Format;
729          return;
730       case GL_PROGRAM_BINDING_ARB:
731          *params = prog->Id;
732          return;
733       case GL_PROGRAM_INSTRUCTIONS_ARB:
734          *params = prog->NumInstructions;
735          return;
736       case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
737          *params = limits->MaxInstructions;
738          return;
739       case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
740          *params = prog->NumNativeInstructions;
741          return;
742       case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
743          *params = limits->MaxNativeInstructions;
744          return;
745       case GL_PROGRAM_TEMPORARIES_ARB:
746          *params = prog->NumTemporaries;
747          return;
748       case GL_MAX_PROGRAM_TEMPORARIES_ARB:
749          *params = limits->MaxTemps;
750          return;
751       case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
752          *params = prog->NumNativeTemporaries;
753          return;
754       case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
755          *params = limits->MaxNativeTemps;
756          return;
757       case GL_PROGRAM_PARAMETERS_ARB:
758          *params = prog->NumParameters;
759          return;
760       case GL_MAX_PROGRAM_PARAMETERS_ARB:
761          *params = limits->MaxParameters;
762          return;
763       case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
764          *params = prog->NumNativeParameters;
765          return;
766       case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
767          *params = limits->MaxNativeParameters;
768          return;
769       case GL_PROGRAM_ATTRIBS_ARB:
770          *params = prog->NumAttributes;
771          return;
772       case GL_MAX_PROGRAM_ATTRIBS_ARB:
773          *params = limits->MaxAttribs;
774          return;
775       case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
776          *params = prog->NumNativeAttributes;
777          return;
778       case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
779          *params = limits->MaxNativeAttribs;
780          return;
781       case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
782          *params = prog->NumAddressRegs;
783          return;
784       case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
785          *params = limits->MaxAddressRegs;
786          return;
787       case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
788          *params = prog->NumNativeAddressRegs;
789          return;
790       case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
791          *params = limits->MaxNativeAddressRegs;
792          return;
793       case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
794          *params = limits->MaxLocalParams;
795          return;
796       case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
797          *params = limits->MaxEnvParams;
798          return;
799       case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
800          /*
801           * XXX we may not really need a driver callback here.
802           * If the number of native instructions, registers, etc. used
803           * are all below the maximums, we could return true.
804           * The spec says that even if this query returns true, there's
805           * no guarantee that the program will run in hardware.
806           */
807          if (prog->Id == 0) {
808             /* default/null program */
809             *params = GL_FALSE;
810          }
811 	 else if (ctx->Driver.IsProgramNative) {
812             /* ask the driver */
813 	    *params = ctx->Driver.IsProgramNative( ctx, target, prog );
814          }
815 	 else {
816             /* probably running in software */
817 	    *params = GL_TRUE;
818          }
819          return;
820       default:
821          /* continue with fragment-program only queries below */
822          break;
823    }
824 
825    /*
826     * The following apply to fragment programs only (at this time)
827     */
828    if (target == GL_FRAGMENT_PROGRAM_ARB) {
829       const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
830       switch (pname) {
831          case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
832             *params = fp->Base.NumNativeAluInstructions;
833             return;
834          case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
835             *params = fp->Base.NumAluInstructions;
836             return;
837          case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
838             *params = fp->Base.NumTexInstructions;
839             return;
840          case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
841             *params = fp->Base.NumNativeTexInstructions;
842             return;
843          case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
844             *params = fp->Base.NumTexIndirections;
845             return;
846          case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
847             *params = fp->Base.NumNativeTexIndirections;
848             return;
849          case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
850             *params = limits->MaxAluInstructions;
851             return;
852          case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
853             *params = limits->MaxNativeAluInstructions;
854             return;
855          case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
856             *params = limits->MaxTexInstructions;
857             return;
858          case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
859             *params = limits->MaxNativeTexInstructions;
860             return;
861          case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
862             *params = limits->MaxTexIndirections;
863             return;
864          case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
865             *params = limits->MaxNativeTexIndirections;
866             return;
867          default:
868             _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
869             return;
870       }
871    } else {
872       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
873       return;
874    }
875 }
876 
877 
878 void GLAPIENTRY
_mesa_GetProgramStringARB(GLenum target,GLenum pname,GLvoid * string)879 _mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
880 {
881    const struct gl_program *prog;
882    char *dst = (char *) string;
883    GET_CURRENT_CONTEXT(ctx);
884 
885    ASSERT_OUTSIDE_BEGIN_END(ctx);
886 
887    if (target == GL_VERTEX_PROGRAM_ARB) {
888       prog = &(ctx->VertexProgram.Current->Base);
889    }
890    else if (target == GL_FRAGMENT_PROGRAM_ARB) {
891       prog = &(ctx->FragmentProgram.Current->Base);
892    }
893    else {
894       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)");
895       return;
896    }
897 
898    ASSERT(prog);
899 
900    if (pname != GL_PROGRAM_STRING_ARB) {
901       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
902       return;
903    }
904 
905    if (prog->String)
906       memcpy(dst, prog->String, strlen((char *) prog->String));
907    else
908       *dst = '\0';
909 }
910