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