program.c revision 82635aad4203d44648dd6e345ec2b5e21ff06510
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5.3
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 program.c
27 * Vertex and fragment program support functions.
28 * \author Brian Paul
29 */
30
31
32#include "glheader.h"
33#include "context.h"
34#include "hash.h"
35#include "program.h"
36#include "prog_parameter.h"
37#include "prog_instruction.h"
38
39
40/**
41 * A pointer to this dummy program is put into the hash table when
42 * glGenPrograms is called.
43 */
44struct gl_program _mesa_DummyProgram;
45
46
47/**
48 * Init context's vertex/fragment program state
49 */
50void
51_mesa_init_program(GLcontext *ctx)
52{
53   GLuint i;
54
55   ctx->Program.ErrorPos = -1;
56   ctx->Program.ErrorString = _mesa_strdup("");
57
58#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
59   ctx->VertexProgram.Enabled = GL_FALSE;
60   ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
61   ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
62   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
63                            ctx->Shared->DefaultVertexProgram);
64   assert(ctx->VertexProgram.Current);
65   for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
66      ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
67      ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
68   }
69#endif
70
71#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
72   ctx->FragmentProgram.Enabled = GL_FALSE;
73   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
74                            ctx->Shared->DefaultFragmentProgram);
75   assert(ctx->FragmentProgram.Current);
76#endif
77
78   /* XXX probably move this stuff */
79#if FEATURE_ATI_fragment_shader
80   ctx->ATIFragmentShader.Enabled = GL_FALSE;
81   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
82   assert(ctx->ATIFragmentShader.Current);
83   ctx->ATIFragmentShader.Current->RefCount++;
84#endif
85}
86
87
88/**
89 * Free a context's vertex/fragment program state
90 */
91void
92_mesa_free_program_data(GLcontext *ctx)
93{
94#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
95   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
96#endif
97#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
98   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
99#endif
100   /* XXX probably move this stuff */
101#if FEATURE_ATI_fragment_shader
102   if (ctx->ATIFragmentShader.Current) {
103      ctx->ATIFragmentShader.Current->RefCount--;
104      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
105         _mesa_free(ctx->ATIFragmentShader.Current);
106      }
107   }
108#endif
109   _mesa_free((void *) ctx->Program.ErrorString);
110}
111
112
113/**
114 * Update the default program objects in the given context to reference those
115 * specified in the shared state and release those referencing the old
116 * shared state.
117 */
118void
119_mesa_update_default_objects_program(GLcontext *ctx)
120{
121#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
122   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
123                            (struct gl_vertex_program *)
124                            ctx->Shared->DefaultVertexProgram);
125   assert(ctx->VertexProgram.Current);
126#endif
127
128#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
129   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
130                            (struct gl_fragment_program *)
131                            ctx->Shared->DefaultFragmentProgram);
132   assert(ctx->FragmentProgram.Current);
133#endif
134
135   /* XXX probably move this stuff */
136#if FEATURE_ATI_fragment_shader
137   if (ctx->ATIFragmentShader.Current) {
138      ctx->ATIFragmentShader.Current->RefCount--;
139      if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
140         _mesa_free(ctx->ATIFragmentShader.Current);
141      }
142   }
143   ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
144   assert(ctx->ATIFragmentShader.Current);
145   ctx->ATIFragmentShader.Current->RefCount++;
146#endif
147}
148
149
150/**
151 * Set the vertex/fragment program error state (position and error string).
152 * This is generally called from within the parsers.
153 */
154void
155_mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
156{
157   ctx->Program.ErrorPos = pos;
158   _mesa_free((void *) ctx->Program.ErrorString);
159   if (!string)
160      string = "";
161   ctx->Program.ErrorString = _mesa_strdup(string);
162}
163
164
165/**
166 * Find the line number and column for 'pos' within 'string'.
167 * Return a copy of the line which contains 'pos'.  Free the line with
168 * _mesa_free().
169 * \param string  the program string
170 * \param pos     the position within the string
171 * \param line    returns the line number corresponding to 'pos'.
172 * \param col     returns the column number corresponding to 'pos'.
173 * \return copy of the line containing 'pos'.
174 */
175const GLubyte *
176_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
177                       GLint *line, GLint *col)
178{
179   const GLubyte *lineStart = string;
180   const GLubyte *p = string;
181   GLubyte *s;
182   int len;
183
184   *line = 1;
185
186   while (p != pos) {
187      if (*p == (GLubyte) '\n') {
188         (*line)++;
189         lineStart = p + 1;
190      }
191      p++;
192   }
193
194   *col = (pos - lineStart) + 1;
195
196   /* return copy of this line */
197   while (*p != 0 && *p != '\n')
198      p++;
199   len = p - lineStart;
200   s = (GLubyte *) _mesa_malloc(len + 1);
201   _mesa_memcpy(s, lineStart, len);
202   s[len] = 0;
203
204   return s;
205}
206
207
208/**
209 * Initialize a new vertex/fragment program object.
210 */
211static struct gl_program *
212_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
213                           GLenum target, GLuint id)
214{
215   (void) ctx;
216   if (prog) {
217      GLuint i;
218      _mesa_bzero(prog, sizeof(*prog));
219      prog->Id = id;
220      prog->Target = target;
221      prog->Resident = GL_TRUE;
222      prog->RefCount = 1;
223      prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
224
225      /* default mapping from samplers to texture units */
226      for (i = 0; i < MAX_SAMPLERS; i++)
227         prog->SamplerUnits[i] = i;
228   }
229
230   return prog;
231}
232
233
234/**
235 * Initialize a new fragment program object.
236 */
237struct gl_program *
238_mesa_init_fragment_program( GLcontext *ctx, struct gl_fragment_program *prog,
239                             GLenum target, GLuint id)
240{
241   if (prog)
242      return _mesa_init_program_struct( ctx, &prog->Base, target, id );
243   else
244      return NULL;
245}
246
247
248/**
249 * Initialize a new vertex program object.
250 */
251struct gl_program *
252_mesa_init_vertex_program( GLcontext *ctx, struct gl_vertex_program *prog,
253                           GLenum target, GLuint id)
254{
255   if (prog)
256      return _mesa_init_program_struct( ctx, &prog->Base, target, id );
257   else
258      return NULL;
259}
260
261
262/**
263 * Allocate and initialize a new fragment/vertex program object but
264 * don't put it into the program hash table.  Called via
265 * ctx->Driver.NewProgram.  May be overridden (ie. replaced) by a
266 * device driver function to implement OO deriviation with additional
267 * types not understood by this function.
268 *
269 * \param ctx  context
270 * \param id   program id/number
271 * \param target  program target/type
272 * \return  pointer to new program object
273 */
274struct gl_program *
275_mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
276{
277   struct gl_program *prog;
278   switch (target) {
279   case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
280      prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
281                                       target, id );
282      break;
283   case GL_FRAGMENT_PROGRAM_NV:
284   case GL_FRAGMENT_PROGRAM_ARB:
285      prog =_mesa_init_fragment_program(ctx,
286                                         CALLOC_STRUCT(gl_fragment_program),
287                                         target, id );
288      break;
289   default:
290      _mesa_problem(ctx, "bad target in _mesa_new_program");
291      prog = NULL;
292   }
293   return prog;
294}
295
296
297/**
298 * Delete a program and remove it from the hash table, ignoring the
299 * reference count.
300 * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
301 * by a device driver function.
302 */
303void
304_mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
305{
306   (void) ctx;
307   ASSERT(prog);
308   ASSERT(prog->RefCount==0);
309
310   if (prog == &_mesa_DummyProgram)
311      return;
312
313   if (prog->String)
314      _mesa_free(prog->String);
315
316   _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
317
318   if (prog->Parameters) {
319      _mesa_free_parameter_list(prog->Parameters);
320   }
321   if (prog->Varying) {
322      _mesa_free_parameter_list(prog->Varying);
323   }
324   if (prog->Attributes) {
325      _mesa_free_parameter_list(prog->Attributes);
326   }
327
328   /* XXX this is a little ugly */
329   if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
330      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
331      if (vprog->TnlData)
332         _mesa_free(vprog->TnlData);
333   }
334
335   _mesa_free(prog);
336}
337
338
339/**
340 * Return the gl_program object for a given ID.
341 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
342 * casts elsewhere.
343 */
344struct gl_program *
345_mesa_lookup_program(GLcontext *ctx, GLuint id)
346{
347   if (id)
348      return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
349   else
350      return NULL;
351}
352
353
354/**
355 * Reference counting for vertex/fragment programs
356 */
357void
358_mesa_reference_program(GLcontext *ctx,
359                        struct gl_program **ptr,
360                        struct gl_program *prog)
361{
362   assert(ptr);
363   if (*ptr && prog) {
364      /* sanity check */
365      ASSERT((*ptr)->Target == prog->Target);
366   }
367   if (*ptr == prog) {
368      return;  /* no change */
369   }
370   if (*ptr) {
371      GLboolean deleteFlag;
372
373      /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
374#if 0
375      printf("Program %p ID=%u Target=%s  Refcount-- to %d\n",
376             *ptr, (*ptr)->Id,
377             ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"),
378             (*ptr)->RefCount - 1);
379#endif
380      ASSERT((*ptr)->RefCount > 0);
381      (*ptr)->RefCount--;
382
383      deleteFlag = ((*ptr)->RefCount == 0);
384      /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
385
386      if (deleteFlag) {
387         ASSERT(ctx);
388         ctx->Driver.DeleteProgram(ctx, *ptr);
389      }
390
391      *ptr = NULL;
392   }
393
394   assert(!*ptr);
395   if (prog) {
396      /*_glthread_LOCK_MUTEX(prog->Mutex);*/
397      prog->RefCount++;
398#if 0
399      printf("Program %p ID=%u Target=%s  Refcount++ to %d\n",
400             prog, prog->Id,
401             (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : "FP"),
402             prog->RefCount);
403#endif
404      /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
405   }
406
407   *ptr = prog;
408}
409
410
411/**
412 * Return a copy of a program.
413 * XXX Problem here if the program object is actually OO-derivation
414 * made by a device driver.
415 */
416struct gl_program *
417_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
418{
419   struct gl_program *clone;
420
421   clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
422   if (!clone)
423      return NULL;
424
425   assert(clone->Target == prog->Target);
426   assert(clone->RefCount == 1);
427
428   clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
429   clone->Format = prog->Format;
430   clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
431   if (!clone->Instructions) {
432      _mesa_reference_program(ctx, &clone, NULL);
433      return NULL;
434   }
435   _mesa_copy_instructions(clone->Instructions, prog->Instructions,
436                           prog->NumInstructions);
437   clone->InputsRead = prog->InputsRead;
438   clone->OutputsWritten = prog->OutputsWritten;
439   clone->SamplersUsed = prog->SamplersUsed;
440   clone->ShadowSamplers = prog->ShadowSamplers;
441   memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
442
443   if (prog->Parameters)
444      clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
445   memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
446   if (prog->Varying)
447      clone->Varying = _mesa_clone_parameter_list(prog->Varying);
448   if (prog->Attributes)
449      clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
450   memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
451   clone->NumInstructions = prog->NumInstructions;
452   clone->NumTemporaries = prog->NumTemporaries;
453   clone->NumParameters = prog->NumParameters;
454   clone->NumAttributes = prog->NumAttributes;
455   clone->NumAddressRegs = prog->NumAddressRegs;
456   clone->NumNativeInstructions = prog->NumNativeInstructions;
457   clone->NumNativeTemporaries = prog->NumNativeTemporaries;
458   clone->NumNativeParameters = prog->NumNativeParameters;
459   clone->NumNativeAttributes = prog->NumNativeAttributes;
460   clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
461   clone->NumAluInstructions = prog->NumAluInstructions;
462   clone->NumTexInstructions = prog->NumTexInstructions;
463   clone->NumTexIndirections = prog->NumTexIndirections;
464   clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
465   clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
466   clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
467
468   switch (prog->Target) {
469   case GL_VERTEX_PROGRAM_ARB:
470      {
471         const struct gl_vertex_program *vp
472            = (const struct gl_vertex_program *) prog;
473         struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
474         vpc->IsPositionInvariant = vp->IsPositionInvariant;
475      }
476      break;
477   case GL_FRAGMENT_PROGRAM_ARB:
478      {
479         const struct gl_fragment_program *fp
480            = (const struct gl_fragment_program *) prog;
481         struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
482         fpc->FogOption = fp->FogOption;
483         fpc->UsesKill = fp->UsesKill;
484      }
485      break;
486   default:
487      _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
488   }
489
490   return clone;
491}
492
493
494/**
495 * Insert 'count' NOP instructions at 'start' in the given program.
496 * Adjust branch targets accordingly.
497 */
498GLboolean
499_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
500{
501   const GLuint origLen = prog->NumInstructions;
502   const GLuint newLen = origLen + count;
503   struct prog_instruction *newInst;
504   GLuint i;
505
506   /* adjust branches */
507   for (i = 0; i < prog->NumInstructions; i++) {
508      struct prog_instruction *inst = prog->Instructions + i;
509      if (inst->BranchTarget > 0) {
510         if (inst->BranchTarget >= start) {
511            inst->BranchTarget += count;
512         }
513      }
514   }
515
516   /* Alloc storage for new instructions */
517   newInst = _mesa_alloc_instructions(newLen);
518   if (!newInst) {
519      return GL_FALSE;
520   }
521
522   /* Copy 'start' instructions into new instruction buffer */
523   _mesa_copy_instructions(newInst, prog->Instructions, start);
524
525   /* init the new instructions */
526   _mesa_init_instructions(newInst + start, count);
527
528   /* Copy the remaining/tail instructions to new inst buffer */
529   _mesa_copy_instructions(newInst + start + count,
530                           prog->Instructions + start,
531                           origLen - start);
532
533   /* free old instructions */
534   _mesa_free_instructions(prog->Instructions, origLen);
535
536   /* install new instructions */
537   prog->Instructions = newInst;
538   prog->NumInstructions = newLen;
539
540   return GL_TRUE;
541}
542
543
544/**
545 * Search instructions for registers that match (oldFile, oldIndex),
546 * replacing them with (newFile, newIndex).
547 */
548static void
549replace_registers(struct prog_instruction *inst, GLuint numInst,
550                  GLuint oldFile, GLuint oldIndex,
551                  GLuint newFile, GLuint newIndex)
552{
553   GLuint i, j;
554   for (i = 0; i < numInst; i++) {
555      /* src regs */
556      for (j = 0; j < _mesa_num_inst_src_regs(inst->Opcode); j++) {
557         if (inst[i].SrcReg[j].File == oldFile &&
558             inst[i].SrcReg[j].Index == oldIndex) {
559            inst[i].SrcReg[j].File = newFile;
560            inst[i].SrcReg[j].Index = newIndex;
561         }
562      }
563      /* dst reg */
564      if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
565         inst[i].DstReg.File = newFile;
566         inst[i].DstReg.Index = newIndex;
567      }
568   }
569}
570
571
572/**
573 * Search instructions for references to program parameters.  When found,
574 * increment the parameter index by 'offset'.
575 * Used when combining programs.
576 */
577static void
578adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
579                     GLuint offset)
580{
581   GLuint i, j;
582   for (i = 0; i < numInst; i++) {
583      for (j = 0; j < _mesa_num_inst_src_regs(inst->Opcode); j++) {
584         GLuint f = inst[i].SrcReg[j].File;
585         if (f == PROGRAM_CONSTANT ||
586             f == PROGRAM_UNIFORM ||
587             f == PROGRAM_STATE_VAR) {
588            inst[i].SrcReg[j].Index += offset;
589         }
590      }
591   }
592}
593
594
595/**
596 * Combine two programs into one.  Fix instructions so the outputs of
597 * the first program go to the inputs of the second program.
598 */
599struct gl_program *
600_mesa_combine_programs(GLcontext *ctx,
601                       const struct gl_program *progA,
602                       const struct gl_program *progB)
603{
604   struct prog_instruction *newInst;
605   struct gl_program *newProg;
606   const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
607   const GLuint lenB = progB->NumInstructions;
608   const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
609   const GLuint newLength = lenA + lenB;
610   GLbitfield inputsB;
611   GLuint i;
612
613   ASSERT(progA->Target == progB->Target);
614
615   newInst = _mesa_alloc_instructions(newLength);
616   if (!newInst)
617      return GL_FALSE;
618
619   _mesa_copy_instructions(newInst, progA->Instructions, lenA);
620   _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
621
622   /* adjust branch / instruction addresses for B's instructions */
623   for (i = 0; i < lenB; i++) {
624      newInst[lenA + i].BranchTarget += lenA;
625   }
626
627   newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
628   newProg->Instructions = newInst;
629   newProg->NumInstructions = newLength;
630
631   if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
632      struct gl_fragment_program *fprogA, *fprogB, *newFprog;
633      fprogA = (struct gl_fragment_program *) progA;
634      fprogB = (struct gl_fragment_program *) progB;
635      newFprog = (struct gl_fragment_program *) newProg;
636
637      newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
638
639      /* Connect color outputs of fprogA to color inputs of fprogB, via a
640       * new temporary register.
641       */
642      if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) &&
643          (progB->InputsRead & (1 << FRAG_ATTRIB_COL0))) {
644         GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY);
645         if (tempReg < 0) {
646            _mesa_problem(ctx, "No free temp regs found in "
647                          "_mesa_combine_programs(), using 31");
648            tempReg = 31;
649         }
650         /* replace writes to result.color[0] with tempReg */
651         replace_registers(newInst, lenA,
652                           PROGRAM_OUTPUT, FRAG_RESULT_COLR,
653                           PROGRAM_TEMPORARY, tempReg);
654         /* replace reads from input.color[0] with tempReg */
655         replace_registers(newInst + lenA, lenB,
656                           PROGRAM_INPUT, FRAG_ATTRIB_COL0,
657                           PROGRAM_TEMPORARY, tempReg);
658      }
659
660      inputsB = progB->InputsRead;
661      if (progA->OutputsWritten & (1 << FRAG_RESULT_COLR)) {
662         inputsB &= ~(1 << FRAG_ATTRIB_COL0);
663      }
664      newProg->InputsRead = progA->InputsRead | inputsB;
665      newProg->OutputsWritten = progB->OutputsWritten;
666      newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
667   }
668   else {
669      /* vertex program */
670      assert(0);      /* XXX todo */
671   }
672
673   /*
674    * Merge parameters (uniforms, constants, etc)
675    */
676   newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
677                                                       progB->Parameters);
678
679   adjust_param_indexes(newInst + lenA, lenB, numParamsA);
680
681
682   return newProg;
683}
684
685
686
687
688/**
689 * Scan the given program to find a free register of the given type.
690 * \param regFile - PROGRAM_INPUT, PROGRAM_OUTPUT or PROGRAM_TEMPORARY
691 */
692GLint
693_mesa_find_free_register(const struct gl_program *prog, GLuint regFile)
694{
695   GLboolean used[MAX_PROGRAM_TEMPS];
696   GLuint i, k;
697
698   assert(regFile == PROGRAM_INPUT ||
699          regFile == PROGRAM_OUTPUT ||
700          regFile == PROGRAM_TEMPORARY);
701
702   _mesa_memset(used, 0, sizeof(used));
703
704   for (i = 0; i < prog->NumInstructions; i++) {
705      const struct prog_instruction *inst = prog->Instructions + i;
706      const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
707
708      for (k = 0; k < n; k++) {
709         if (inst->SrcReg[k].File == regFile) {
710            used[inst->SrcReg[k].Index] = GL_TRUE;
711         }
712      }
713   }
714
715   for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
716      if (!used[i])
717         return i;
718   }
719
720   return -1;
721}
722
723
724
725/**
726 * Mixing ARB and NV vertex/fragment programs can be tricky.
727 * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
728 *  but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
729 * The two different fragment program targets are supposed to be compatible
730 * to some extent (see GL_ARB_fragment_program spec).
731 * This function does the compatibility check.
732 */
733static GLboolean
734compatible_program_targets(GLenum t1, GLenum t2)
735{
736   if (t1 == t2)
737      return GL_TRUE;
738   if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
739      return GL_TRUE;
740   if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
741      return GL_TRUE;
742   return GL_FALSE;
743}
744
745
746
747/**********************************************************************/
748/* API functions                                                      */
749/**********************************************************************/
750
751
752/**
753 * Bind a program (make it current)
754 * \note Called from the GL API dispatcher by both glBindProgramNV
755 * and glBindProgramARB.
756 */
757void GLAPIENTRY
758_mesa_BindProgram(GLenum target, GLuint id)
759{
760   struct gl_program *curProg, *newProg;
761   GET_CURRENT_CONTEXT(ctx);
762   ASSERT_OUTSIDE_BEGIN_END(ctx);
763
764   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
765
766   /* Error-check target and get curProg */
767   if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
768        (ctx->Extensions.NV_vertex_program ||
769         ctx->Extensions.ARB_vertex_program)) {
770      curProg = &ctx->VertexProgram.Current->Base;
771   }
772   else if ((target == GL_FRAGMENT_PROGRAM_NV
773             && ctx->Extensions.NV_fragment_program) ||
774            (target == GL_FRAGMENT_PROGRAM_ARB
775             && ctx->Extensions.ARB_fragment_program)) {
776      curProg = &ctx->FragmentProgram.Current->Base;
777   }
778   else {
779      _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
780      return;
781   }
782
783   /*
784    * Get pointer to new program to bind.
785    * NOTE: binding to a non-existant program is not an error.
786    * That's supposed to be caught in glBegin.
787    */
788   if (id == 0) {
789      /* Bind a default program */
790      newProg = NULL;
791      if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
792         newProg = &ctx->Shared->DefaultVertexProgram->Base;
793      else
794         newProg = &ctx->Shared->DefaultFragmentProgram->Base;
795   }
796   else {
797      /* Bind a user program */
798      newProg = _mesa_lookup_program(ctx, id);
799      if (!newProg || newProg == &_mesa_DummyProgram) {
800         /* allocate a new program now */
801         newProg = ctx->Driver.NewProgram(ctx, target, id);
802         if (!newProg) {
803            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
804            return;
805         }
806         _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
807      }
808      else if (!compatible_program_targets(newProg->Target, target)) {
809         _mesa_error(ctx, GL_INVALID_OPERATION,
810                     "glBindProgramNV/ARB(target mismatch)");
811         return;
812      }
813   }
814
815   /** All error checking is complete now **/
816
817   if (curProg->Id == id) {
818      /* binding same program - no change */
819      return;
820   }
821
822   /* bind newProg */
823   if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
824      _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
825                               (struct gl_vertex_program *) newProg);
826   }
827   else if (target == GL_FRAGMENT_PROGRAM_NV ||
828            target == GL_FRAGMENT_PROGRAM_ARB) {
829      _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
830                               (struct gl_fragment_program *) newProg);
831   }
832
833   /* Never null pointers */
834   ASSERT(ctx->VertexProgram.Current);
835   ASSERT(ctx->FragmentProgram.Current);
836
837   if (ctx->Driver.BindProgram)
838      ctx->Driver.BindProgram(ctx, target, newProg);
839}
840
841
842/**
843 * Delete a list of programs.
844 * \note Not compiled into display lists.
845 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
846 */
847void GLAPIENTRY
848_mesa_DeletePrograms(GLsizei n, const GLuint *ids)
849{
850   GLint i;
851   GET_CURRENT_CONTEXT(ctx);
852   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
853
854   if (n < 0) {
855      _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
856      return;
857   }
858
859   for (i = 0; i < n; i++) {
860      if (ids[i] != 0) {
861         struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
862         if (prog == &_mesa_DummyProgram) {
863            _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
864         }
865         else if (prog) {
866            /* Unbind program if necessary */
867            if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */
868                prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
869               if (ctx->VertexProgram.Current &&
870                   ctx->VertexProgram.Current->Base.Id == ids[i]) {
871                  /* unbind this currently bound program */
872                  _mesa_BindProgram(prog->Target, 0);
873               }
874            }
875            else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
876                     prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
877               if (ctx->FragmentProgram.Current &&
878                   ctx->FragmentProgram.Current->Base.Id == ids[i]) {
879                  /* unbind this currently bound program */
880                  _mesa_BindProgram(prog->Target, 0);
881               }
882            }
883            else {
884               _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
885               return;
886            }
887            /* The ID is immediately available for re-use now */
888            _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
889            _mesa_reference_program(ctx, &prog, NULL);
890         }
891      }
892   }
893}
894
895
896/**
897 * Generate a list of new program identifiers.
898 * \note Not compiled into display lists.
899 * \note Called by both glGenProgramsNV and glGenProgramsARB.
900 */
901void GLAPIENTRY
902_mesa_GenPrograms(GLsizei n, GLuint *ids)
903{
904   GLuint first;
905   GLuint i;
906   GET_CURRENT_CONTEXT(ctx);
907   ASSERT_OUTSIDE_BEGIN_END(ctx);
908
909   if (n < 0) {
910      _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
911      return;
912   }
913
914   if (!ids)
915      return;
916
917   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
918
919   /* Insert pointer to dummy program as placeholder */
920   for (i = 0; i < (GLuint) n; i++) {
921      _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
922   }
923
924   /* Return the program names */
925   for (i = 0; i < (GLuint) n; i++) {
926      ids[i] = first + i;
927   }
928}
929