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