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