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