1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file prog_statevars.c
27 * Program state variable management.
28 * \author Brian Paul
29 */
30
31
32#include <stdio.h>
33#include <stddef.h>
34#include "main/glheader.h"
35#include "main/context.h"
36#include "main/blend.h"
37
38#include "main/macros.h"
39#include "main/mtypes.h"
40#include "main/fbobject.h"
41#include "prog_statevars.h"
42#include "prog_parameter.h"
43#include "main/samplerobj.h"
44#include "main/framebuffer.h"
45
46
47#define ONE_DIV_SQRT_LN2 (1.201122408786449815)
48
49static ALWAYS_INLINE void
50copy_matrix(float *value, const float *m, unsigned firstRow, unsigned lastRow)
51{
52   unsigned i, row;
53
54   assert(firstRow < 4);
55   assert(lastRow < 4);
56
57   for (i = 0, row = firstRow; row <= lastRow; row++) {
58      value[i++] = m[row + 0];
59      value[i++] = m[row + 4];
60      value[i++] = m[row + 8];
61      value[i++] = m[row + 12];
62   }
63}
64
65static ALWAYS_INLINE void
66copy_matrix_transposed(float *value, const float *m, unsigned firstRow, unsigned lastRow)
67{
68   assert(firstRow < 4);
69   assert(lastRow < 4);
70
71   memcpy(value, &m[firstRow * 4],
72          (lastRow - firstRow + 1) * 4 * sizeof(GLfloat));
73}
74
75/**
76 * Use the list of tokens in the state[] array to find global GL state
77 * and return it in <value>.  Usually, four values are returned in <value>
78 * but matrix queries may return as many as 16 values.
79 * This function is used for ARB vertex/fragment programs.
80 * The program parser will produce the state[] values.
81 */
82static void
83fetch_state(struct gl_context *ctx, const gl_state_index16 state[],
84            gl_constant_value *val)
85{
86   GLfloat *value = &val->f;
87
88   switch (state[0]) {
89   case STATE_MATERIAL:
90      {
91         /* state[1] is MAT_ATTRIB_FRONT_* */
92         const GLuint index = (GLuint) state[1];
93         const struct gl_material *mat = &ctx->Light.Material;
94         assert(index >= MAT_ATTRIB_FRONT_AMBIENT &&
95                index <= MAT_ATTRIB_BACK_SHININESS);
96         if (index >= MAT_ATTRIB_FRONT_SHININESS) {
97            value[0] = mat->Attrib[index][0];
98            value[1] = 0.0F;
99            value[2] = 0.0F;
100            value[3] = 1.0F;
101         } else {
102            COPY_4V(value, mat->Attrib[index]);
103         }
104         return;
105      }
106   case STATE_LIGHT:
107      {
108         /* state[1] is the light number */
109         const GLuint ln = (GLuint) state[1];
110         /* state[2] is the light attribute */
111         const unsigned index = state[2] - STATE_AMBIENT;
112         assert(index < 8);
113         if (index != STATE_SPOT_CUTOFF)
114            COPY_4V(value, (float*)&ctx->Light.LightSource[ln] + index * 4);
115         else
116            value[0] = ctx->Light.LightSource[ln].SpotCutoff;
117         return;
118      }
119   case STATE_LIGHT_ARRAY: {
120      /* This must be exact because it must match the gl_LightSource layout
121       * in GLSL.
122       */
123      STATIC_ASSERT(sizeof(struct gl_light_uniforms) == 29 * 4);
124      STATIC_ASSERT(ARRAY_SIZE(ctx->Light.LightSourceData) == 29 * MAX_LIGHTS);
125      /* state[1] is the index of the first value */
126      /* state[2] is the number of values */
127      assert(state[1] + state[2] <= ARRAY_SIZE(ctx->Light.LightSourceData));
128      memcpy(value, &ctx->Light.LightSourceData[state[1]],
129             state[2] * sizeof(float));
130      return;
131   }
132   case STATE_LIGHT_ATTENUATION_ARRAY: {
133      const unsigned first = state[1];
134      const unsigned num_lights = state[2];
135      for (unsigned i = 0; i < num_lights; i++) {
136         COPY_4V(value,
137                 &ctx->Light.LightSource[first + i].ConstantAttenuation);
138         value += 4;
139      }
140      return;
141   }
142   case STATE_LIGHTMODEL_AMBIENT:
143      COPY_4V(value, ctx->Light.Model.Ambient);
144      return;
145   case STATE_LIGHTMODEL_SCENECOLOR:
146      if (state[1] == 0) {
147         /* front */
148         GLint i;
149         for (i = 0; i < 3; i++) {
150            value[i] = ctx->Light.Model.Ambient[i]
151               * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
152               + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
153         }
154	 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
155      }
156      else {
157         /* back */
158         GLint i;
159         for (i = 0; i < 3; i++) {
160            value[i] = ctx->Light.Model.Ambient[i]
161               * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
162               + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
163         }
164	 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
165      }
166      return;
167   case STATE_LIGHTPROD:
168      {
169         const GLuint ln = (GLuint) state[1];
170         const GLuint index = (GLuint) state[2];
171         const GLuint attr = (index / 2) * 4;
172         assert(index >= MAT_ATTRIB_FRONT_AMBIENT &&
173                index <= MAT_ATTRIB_BACK_SPECULAR);
174         for (int i = 0; i < 3; i++) {
175            /* We want attr to access out of bounds into the following Diffuse
176             * and Specular fields. This is guaranteed to work because
177             * STATE_LIGHT and STATE_LIGHT_ARRAY also rely on this memory
178             * layout.
179             */
180            STATIC_ASSERT(offsetof(struct gl_light_uniforms, Ambient) + 16 ==
181                          offsetof(struct gl_light_uniforms, Diffuse));
182            STATIC_ASSERT(offsetof(struct gl_light_uniforms, Diffuse) + 16 ==
183                          offsetof(struct gl_light_uniforms, Specular));
184            value[i] = ctx->Light.LightSource[ln].Ambient[attr + i] *
185                       ctx->Light.Material.Attrib[index][i];
186         }
187         /* [3] = material alpha */
188         value[3] = ctx->Light.Material.Attrib[index][3];
189         return;
190      }
191   case STATE_LIGHTPROD_ARRAY_FRONT: {
192      const unsigned first_light = state[1];
193      const unsigned num_lights = state[2];
194
195      for (unsigned i = 0; i < num_lights; i++) {
196         unsigned light = first_light + i;
197
198         for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT;
199              attrib <= MAT_ATTRIB_FRONT_SPECULAR; attrib += 2) {
200            for (int chan = 0; chan < 3; chan++) {
201               /* We want offset to access out of bounds into the following
202                * Diffuse and Specular fields. This is guaranteed to work
203                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
204                * on this memory layout.
205                */
206               unsigned offset = (attrib / 2) * 4 + chan;
207               *value++ =
208                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
209                  ctx->Light.Material.Attrib[attrib][chan];
210            }
211            /* [3] = material alpha */
212            *value++ = ctx->Light.Material.Attrib[attrib][3];
213         }
214      }
215      return;
216   }
217   case STATE_LIGHTPROD_ARRAY_BACK: {
218      const unsigned first_light = state[1];
219      const unsigned num_lights = state[2];
220
221      for (unsigned i = 0; i < num_lights; i++) {
222         unsigned light = first_light + i;
223
224         for (unsigned attrib = MAT_ATTRIB_BACK_AMBIENT;
225              attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib += 2) {
226            for (int chan = 0; chan < 3; chan++) {
227               /* We want offset to access out of bounds into the following
228                * Diffuse and Specular fields. This is guaranteed to work
229                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
230                * on this memory layout.
231                */
232               unsigned offset = (attrib / 2) * 4 + chan;
233               *value++ =
234                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
235                  ctx->Light.Material.Attrib[attrib][chan];
236            }
237            /* [3] = material alpha */
238            *value++ = ctx->Light.Material.Attrib[attrib][3];
239         }
240      }
241      return;
242   }
243   case STATE_LIGHTPROD_ARRAY_TWOSIDE: {
244      const unsigned first_light = state[1];
245      const unsigned num_lights = state[2];
246
247      for (unsigned i = 0; i < num_lights; i++) {
248         unsigned light = first_light + i;
249
250         for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT;
251              attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib++) {
252            for (int chan = 0; chan < 3; chan++) {
253               /* We want offset to access out of bounds into the following
254                * Diffuse and Specular fields. This is guaranteed to work
255                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
256                * on this memory layout.
257                */
258               unsigned offset = (attrib / 2) * 4 + chan;
259               *value++ =
260                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
261                  ctx->Light.Material.Attrib[attrib][chan];
262            }
263            /* [3] = material alpha */
264            *value++ = ctx->Light.Material.Attrib[attrib][3];
265         }
266      }
267      return;
268   }
269   case STATE_TEXGEN:
270      {
271         /* state[1] is the texture unit */
272         const GLuint unit = (GLuint) state[1];
273         /* state[2] is the texgen attribute */
274         /* Assertions for the expected memory layout. */
275#define MEMBER_SIZEOF(type, member) sizeof(((type *)0)->member)
276         STATIC_ASSERT(MEMBER_SIZEOF(struct gl_fixedfunc_texture_unit,
277                                     EyePlane[0]) == 4 * sizeof(float));
278         STATIC_ASSERT(MEMBER_SIZEOF(struct gl_fixedfunc_texture_unit,
279                                     ObjectPlane[0]) == 4 * sizeof(float));
280#undef MEMBER_SIZEOF
281         STATIC_ASSERT(STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S == GEN_T - GEN_S);
282         STATIC_ASSERT(STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S == GEN_R - GEN_S);
283         STATIC_ASSERT(STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S == GEN_Q - GEN_S);
284         STATIC_ASSERT(offsetof(struct gl_fixedfunc_texture_unit, ObjectPlane) -
285                       offsetof(struct gl_fixedfunc_texture_unit, EyePlane) ==
286                       (STATE_TEXGEN_OBJECT_S - STATE_TEXGEN_EYE_S) * 4 * sizeof(float));
287         STATIC_ASSERT(STATE_TEXGEN_OBJECT_T - STATE_TEXGEN_OBJECT_S == GEN_T - GEN_S);
288         STATIC_ASSERT(STATE_TEXGEN_OBJECT_R - STATE_TEXGEN_OBJECT_S == GEN_R - GEN_S);
289         STATIC_ASSERT(STATE_TEXGEN_OBJECT_Q - STATE_TEXGEN_OBJECT_S == GEN_Q - GEN_S);
290
291         const float *attr = (float*)ctx->Texture.FixedFuncUnit[unit].EyePlane +
292                             (state[2] - STATE_TEXGEN_EYE_S) * 4;
293         COPY_4V(value, attr);
294         return;
295      }
296   case STATE_TEXENV_COLOR:
297      {
298         /* state[1] is the texture unit */
299         const GLuint unit = (GLuint) state[1];
300         if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer))
301            COPY_4V(value, ctx->Texture.FixedFuncUnit[unit].EnvColor);
302         else
303            COPY_4V(value, ctx->Texture.FixedFuncUnit[unit].EnvColorUnclamped);
304      }
305      return;
306   case STATE_FOG_COLOR:
307      if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer))
308         COPY_4V(value, ctx->Fog.Color);
309      else
310         COPY_4V(value, ctx->Fog.ColorUnclamped);
311      return;
312   case STATE_FOG_PARAMS:
313      value[0] = ctx->Fog.Density;
314      value[1] = ctx->Fog.Start;
315      value[2] = ctx->Fog.End;
316      value[3] = 1.0f / (ctx->Fog.End - ctx->Fog.Start);
317      return;
318   case STATE_CLIPPLANE:
319      {
320         const GLuint plane = (GLuint) state[1];
321         COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
322      }
323      return;
324   case STATE_POINT_SIZE:
325      value[0] = ctx->Point.Size;
326      value[1] = ctx->Point.MinSize;
327      value[2] = ctx->Point.MaxSize;
328      value[3] = ctx->Point.Threshold;
329      return;
330   case STATE_POINT_ATTENUATION:
331      value[0] = ctx->Point.Params[0];
332      value[1] = ctx->Point.Params[1];
333      value[2] = ctx->Point.Params[2];
334      value[3] = 1.0F;
335      return;
336   /* state[0] = modelview, projection, texture, etc. */
337   /* state[1] = which texture matrix or program matrix */
338   /* state[2] = first row to fetch */
339   /* state[3] = last row to fetch */
340   case STATE_MODELVIEW_MATRIX: {
341      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
342      copy_matrix(value, matrix->m, state[2], state[3]);
343      return;
344   }
345   case STATE_MODELVIEW_MATRIX_INVERSE: {
346      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
347      copy_matrix(value, matrix->inv, state[2], state[3]);
348      return;
349   }
350   case STATE_MODELVIEW_MATRIX_TRANSPOSE: {
351      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
352      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
353      return;
354   }
355   case STATE_MODELVIEW_MATRIX_INVTRANS: {
356      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
357      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
358      return;
359   }
360   case STATE_PROJECTION_MATRIX: {
361      const GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
362      copy_matrix(value, matrix->m, state[2], state[3]);
363      return;
364   }
365   case STATE_PROJECTION_MATRIX_INVERSE: {
366      GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
367      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
368      copy_matrix(value, matrix->inv, state[2], state[3]);
369      return;
370   }
371   case STATE_PROJECTION_MATRIX_TRANSPOSE: {
372      const GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
373      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
374      return;
375   }
376   case STATE_PROJECTION_MATRIX_INVTRANS: {
377      GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
378      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
379      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
380      return;
381   }
382   case STATE_MVP_MATRIX: {
383      const GLmatrix *matrix = &ctx->_ModelProjectMatrix;
384      copy_matrix(value, matrix->m, state[2], state[3]);
385      return;
386   }
387   case STATE_MVP_MATRIX_INVERSE: {
388      GLmatrix *matrix = &ctx->_ModelProjectMatrix;
389      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
390      copy_matrix(value, matrix->inv, state[2], state[3]);
391      return;
392   }
393   case STATE_MVP_MATRIX_TRANSPOSE: {
394      const GLmatrix *matrix = &ctx->_ModelProjectMatrix;
395      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
396      return;
397   }
398   case STATE_MVP_MATRIX_INVTRANS: {
399      GLmatrix *matrix = &ctx->_ModelProjectMatrix;
400      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
401      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
402      return;
403   }
404   case STATE_TEXTURE_MATRIX: {
405      const GLuint index = (GLuint) state[1];
406      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
407      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
408      copy_matrix(value, matrix->m, state[2], state[3]);
409      return;
410   }
411   case STATE_TEXTURE_MATRIX_INVERSE: {
412      const GLuint index = (GLuint) state[1];
413      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
414      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
415      copy_matrix(value, matrix->inv, state[2], state[3]);
416      return;
417   }
418   case STATE_TEXTURE_MATRIX_TRANSPOSE: {
419      const GLuint index = (GLuint) state[1];
420      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
421      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
422      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
423      return;
424   }
425   case STATE_TEXTURE_MATRIX_INVTRANS: {
426      const GLuint index = (GLuint) state[1];
427      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
428      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
429      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
430      return;
431   }
432   case STATE_PROGRAM_MATRIX: {
433      const GLuint index = (GLuint) state[1];
434      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
435      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
436      copy_matrix(value, matrix->m, state[2], state[3]);
437      return;
438   }
439   case STATE_PROGRAM_MATRIX_INVERSE: {
440      const GLuint index = (GLuint) state[1];
441      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
442      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
443      _math_matrix_analyse((GLmatrix*)matrix); /* Be sure inverse is up to date: */
444      copy_matrix(value, matrix->inv, state[2], state[3]);
445      return;
446   }
447   case STATE_PROGRAM_MATRIX_TRANSPOSE: {
448      const GLuint index = (GLuint) state[1];
449      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
450      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
451      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
452      return;
453   }
454   case STATE_PROGRAM_MATRIX_INVTRANS: {
455      const GLuint index = (GLuint) state[1];
456      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
457      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
458      _math_matrix_analyse((GLmatrix*)matrix); /* Be sure inverse is up to date: */
459      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
460      return;
461   }
462   case STATE_NUM_SAMPLES:
463      val[0].i = MAX2(1, _mesa_geometric_samples(ctx->DrawBuffer));
464      return;
465   case STATE_DEPTH_RANGE:
466      value[0] = ctx->ViewportArray[0].Near;                /* near       */
467      value[1] = ctx->ViewportArray[0].Far;                 /* far        */
468      value[2] = ctx->ViewportArray[0].Far - ctx->ViewportArray[0].Near; /* far - near */
469      value[3] = 1.0;
470      return;
471   case STATE_FRAGMENT_PROGRAM_ENV: {
472      const int idx = (int) state[1];
473      COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
474      return;
475   }
476   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY: {
477      const unsigned idx = state[1];
478      const unsigned bytes = state[2] * 16;
479      memcpy(value, ctx->FragmentProgram.Parameters[idx], bytes);
480      return;
481   }
482   case STATE_FRAGMENT_PROGRAM_LOCAL: {
483      float (*params)[4] = ctx->FragmentProgram.Current->arb.LocalParams;
484      if (unlikely(!params)) {
485         /* Local parameters haven't been allocated yet.
486          * ARB_fragment_program says that local parameters are
487          * "initially set to (0,0,0,0)." Return that.
488          */
489         memset(value, 0, sizeof(float) * 4);
490         return;
491      }
492
493      const int idx = (int) state[1];
494      COPY_4V(value, params[idx]);
495      return;
496   }
497   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY: {
498      const unsigned idx = state[1];
499      const unsigned bytes = state[2] * 16;
500      float (*params)[4] = ctx->FragmentProgram.Current->arb.LocalParams;
501      if (!params) {
502         /* Local parameters haven't been allocated yet.
503          * ARB_fragment_program says that local parameters are
504          * "initially set to (0,0,0,0)." Return that.
505          */
506         memset(value, 0, bytes);
507         return;
508      }
509      memcpy(value, params[idx], bytes);
510      return;
511   }
512   case STATE_VERTEX_PROGRAM_ENV: {
513      const int idx = (int) state[1];
514      COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
515      return;
516   }
517   case STATE_VERTEX_PROGRAM_ENV_ARRAY: {
518      const unsigned idx = state[1];
519      const unsigned bytes = state[2] * 16;
520      memcpy(value, ctx->VertexProgram.Parameters[idx], bytes);
521      return;
522   }
523   case STATE_VERTEX_PROGRAM_LOCAL: {
524      float (*params)[4] = ctx->VertexProgram.Current->arb.LocalParams;
525      if (unlikely(!params)) {
526         /* Local parameters haven't been allocated yet.
527          * ARB_vertex_program says that local parameters are
528          * "initially set to (0,0,0,0)." Return that.
529          */
530         memset(value, 0, sizeof(float) * 4);
531         return;
532      }
533
534      const int idx = (int) state[1];
535      COPY_4V(value, params[idx]);
536      return;
537   }
538   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY: {
539      const unsigned idx = state[1];
540      const unsigned bytes = state[2] * 16;
541      float (*params)[4] = ctx->VertexProgram.Current->arb.LocalParams;
542      if (!params) {
543         /* Local parameters haven't been allocated yet.
544          * ARB_vertex_program says that local parameters are
545          * "initially set to (0,0,0,0)." Return that.
546          */
547         memset(value, 0, bytes);
548         return;
549      }
550      memcpy(value, params[idx], bytes);
551      return;
552   }
553
554   case STATE_NORMAL_SCALE_EYESPACE:
555      ASSIGN_4V(value, ctx->_ModelViewInvScaleEyespace, 0, 0, 1);
556      return;
557
558   case STATE_CURRENT_ATTRIB:
559      {
560         const GLuint idx = (GLuint) state[1];
561         COPY_4V(value, ctx->Current.Attrib[idx]);
562      }
563      return;
564
565   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
566      {
567         const GLuint idx = (GLuint) state[1];
568         if(ctx->Light._ClampVertexColor &&
569            (idx == VERT_ATTRIB_COLOR0 ||
570             idx == VERT_ATTRIB_COLOR1)) {
571            value[0] = SATURATE(ctx->Current.Attrib[idx][0]);
572            value[1] = SATURATE(ctx->Current.Attrib[idx][1]);
573            value[2] = SATURATE(ctx->Current.Attrib[idx][2]);
574            value[3] = SATURATE(ctx->Current.Attrib[idx][3]);
575         }
576         else
577            COPY_4V(value, ctx->Current.Attrib[idx]);
578      }
579      return;
580
581   case STATE_NORMAL_SCALE:
582      ASSIGN_4V(value,
583                ctx->_ModelViewInvScale,
584                ctx->_ModelViewInvScale,
585                ctx->_ModelViewInvScale,
586                1);
587      return;
588
589   case STATE_FOG_PARAMS_OPTIMIZED: {
590      /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog)
591       * might be more expensive than EX2 on some hw, plus it needs
592       * another constant (e) anyway. Linear fog can now be done with a
593       * single MAD.
594       * linear: fogcoord * -1/(end-start) + end/(end-start)
595       * exp: 2^-(density/ln(2) * fogcoord)
596       * exp2: 2^-((density/(sqrt(ln(2))) * fogcoord)^2)
597       */
598      float val =  (ctx->Fog.End == ctx->Fog.Start)
599         ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start));
600      value[0] = val;
601      value[1] = ctx->Fog.End * -val;
602      value[2] = (GLfloat)(ctx->Fog.Density * M_LOG2E); /* M_LOG2E == 1/ln(2) */
603      value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2);
604      return;
605   }
606
607   case STATE_POINT_SIZE_CLAMPED:
608      {
609        /* this includes implementation dependent limits, to avoid
610         * another potentially necessary clamp.
611         * Note: for sprites, point smooth (point AA) is ignored
612         * and we'll clamp to MinPointSizeAA and MaxPointSize, because we
613         * expect drivers will want to say their minimum for AA size is 0.0
614         * but for non-AA it's 1.0 (because normal points with size below 1.0
615         * need to get rounded up to 1.0, hence never disappear). GL does
616         * not specify max clamp size for sprites, other than it needs to be
617         * at least as large as max AA size, hence use non-AA size there.
618         */
619         GLfloat minImplSize;
620         GLfloat maxImplSize;
621         if (ctx->Point.PointSprite) {
622            minImplSize = ctx->Const.MinPointSizeAA;
623            maxImplSize = ctx->Const.MaxPointSize;
624         }
625         else if (ctx->Point.SmoothFlag || _mesa_is_multisample_enabled(ctx)) {
626            minImplSize = ctx->Const.MinPointSizeAA;
627            maxImplSize = ctx->Const.MaxPointSizeAA;
628         }
629         else {
630            minImplSize = ctx->Const.MinPointSize;
631            maxImplSize = ctx->Const.MaxPointSize;
632         }
633         value[0] = ctx->Point.Size;
634         value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize;
635         value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize;
636         value[3] = ctx->Point.Threshold;
637      }
638      return;
639   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
640      {
641         /* here, state[1] is the light number */
642         /* pre-normalize spot dir */
643         const GLuint ln = (GLuint) state[1];
644         COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection);
645         value[3] = ctx->Light.LightSource[ln]._CosCutoff;
646      }
647      return;
648
649   case STATE_LIGHT_POSITION:
650      {
651         const GLuint ln = (GLuint) state[1];
652         COPY_4V(value, ctx->Light.Light[ln]._Position);
653      }
654      return;
655
656   case STATE_LIGHT_POSITION_ARRAY: {
657      const unsigned first = state[1];
658      const unsigned num_lights = state[2];
659      for (unsigned i = 0; i < num_lights; i++) {
660         COPY_4V(value, ctx->Light.Light[first + i]._Position);
661         value += 4;
662      }
663      return;
664   }
665
666   case STATE_LIGHT_POSITION_NORMALIZED:
667      {
668         const GLuint ln = (GLuint) state[1];
669         float p[4];
670         COPY_4V(p, ctx->Light.Light[ln]._Position);
671         NORMALIZE_3FV(p);
672         COPY_4V(value, p);
673      }
674      return;
675
676   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY: {
677      const unsigned first = state[1];
678      const unsigned num_lights = state[2];
679      for (unsigned i = 0; i < num_lights; i++) {
680         float p[4];
681         COPY_4V(p, ctx->Light.Light[first + i]._Position);
682         NORMALIZE_3FV(p);
683         COPY_4V(value, p);
684         value += 4;
685      }
686      return;
687   }
688
689   case STATE_LIGHT_HALF_VECTOR:
690      {
691         const GLuint ln = (GLuint) state[1];
692         GLfloat p[3];
693         /* Compute infinite half angle vector:
694          *   halfVector = normalize(normalize(lightPos) + (0, 0, 1))
695          * light.EyePosition.w should be 0 for infinite lights.
696          */
697         COPY_3V(p, ctx->Light.Light[ln]._Position);
698         NORMALIZE_3FV(p);
699         ADD_3V(p, p, ctx->_EyeZDir);
700         NORMALIZE_3FV(p);
701         COPY_3V(value, p);
702         value[3] = 1.0;
703      }
704      return;
705
706   case STATE_PT_SCALE:
707      value[0] = ctx->Pixel.RedScale;
708      value[1] = ctx->Pixel.GreenScale;
709      value[2] = ctx->Pixel.BlueScale;
710      value[3] = ctx->Pixel.AlphaScale;
711      return;
712
713   case STATE_PT_BIAS:
714      value[0] = ctx->Pixel.RedBias;
715      value[1] = ctx->Pixel.GreenBias;
716      value[2] = ctx->Pixel.BlueBias;
717      value[3] = ctx->Pixel.AlphaBias;
718      return;
719
720   case STATE_FB_SIZE:
721      value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1);
722      value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
723      value[2] = 0.0F;
724      value[3] = 0.0F;
725      return;
726
727   case STATE_FB_WPOS_Y_TRANSFORM:
728      /* A driver may negate this conditional by using ZW swizzle
729       * instead of XY (based on e.g. some other state). */
730      if (!ctx->DrawBuffer->FlipY) {
731         /* Identity (XY) followed by flipping Y upside down (ZW). */
732         value[0] = 1.0F;
733         value[1] = 0.0F;
734         value[2] = -1.0F;
735         value[3] = _mesa_geometric_height(ctx->DrawBuffer);
736      } else {
737         /* Flipping Y upside down (XY) followed by identity (ZW). */
738         value[0] = -1.0F;
739         value[1] = _mesa_geometric_height(ctx->DrawBuffer);
740         value[2] = 1.0F;
741         value[3] = 0.0F;
742      }
743      return;
744
745   case STATE_FB_PNTC_Y_TRANSFORM:
746      {
747         bool flip_y = (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) ^
748            (ctx->DrawBuffer->FlipY);
749
750         value[0] = flip_y ? -1.0F : 1.0F;
751         value[1] = flip_y ? 1.0F : 0.0F;
752         value[2] = 0.0F;
753         value[3] = 0.0F;
754      }
755      return;
756
757   case STATE_TCS_PATCH_VERTICES_IN:
758      val[0].i = ctx->TessCtrlProgram.patch_vertices;
759      return;
760
761   case STATE_TES_PATCH_VERTICES_IN:
762      if (ctx->TessCtrlProgram._Current)
763         val[0].i = ctx->TessCtrlProgram._Current->info.tess.tcs_vertices_out;
764      else
765         val[0].i = ctx->TessCtrlProgram.patch_vertices;
766      return;
767
768   case STATE_ADVANCED_BLENDING_MODE:
769      val[0].i = _mesa_get_advanced_blend_sh_constant(
770                   ctx->Color.BlendEnabled, ctx->Color._AdvancedBlendMode);
771      return;
772
773   case STATE_ALPHA_REF:
774      value[0] = ctx->Color.AlphaRefUnclamped;
775      return;
776
777   case STATE_CLIP_INTERNAL:
778      {
779         const GLuint plane = (GLuint) state[1];
780         COPY_4V(value, ctx->Transform._ClipUserPlane[plane]);
781      }
782      return;
783   }
784}
785
786unsigned
787_mesa_program_state_value_size(const gl_state_index16 state[STATE_LENGTH])
788{
789   if (state[0] == STATE_LIGHT && state[2] == STATE_SPOT_CUTOFF)
790      return 1;
791
792   /* Everything else is packed into vec4s */
793   return 4;
794}
795
796/**
797 * Return a bitmask of the Mesa state flags (_NEW_* values) which would
798 * indicate that the given context state may have changed.
799 * The bitmask is used during validation to determine if we need to update
800 * vertex/fragment program parameters (like "state.material.color") when
801 * some GL state has changed.
802 */
803GLbitfield
804_mesa_program_state_flags(const gl_state_index16 state[STATE_LENGTH])
805{
806   switch (state[0]) {
807   case STATE_MATERIAL:
808      return _NEW_MATERIAL;
809
810   case STATE_LIGHTPROD:
811   case STATE_LIGHTPROD_ARRAY_FRONT:
812   case STATE_LIGHTPROD_ARRAY_BACK:
813   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
814   case STATE_LIGHTMODEL_SCENECOLOR:
815      return _NEW_LIGHT_CONSTANTS | _NEW_MATERIAL;
816
817   case STATE_LIGHT:
818   case STATE_LIGHT_ARRAY:
819   case STATE_LIGHT_ATTENUATION_ARRAY:
820   case STATE_LIGHTMODEL_AMBIENT:
821   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
822   case STATE_LIGHT_POSITION:
823   case STATE_LIGHT_POSITION_ARRAY:
824   case STATE_LIGHT_POSITION_NORMALIZED:
825   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
826   case STATE_LIGHT_HALF_VECTOR:
827      return _NEW_LIGHT_CONSTANTS;
828
829   case STATE_TEXGEN:
830      return _NEW_TEXTURE_STATE;
831   case STATE_TEXENV_COLOR:
832      return _NEW_TEXTURE_STATE | _NEW_BUFFERS | _NEW_FRAG_CLAMP;
833
834   case STATE_FOG_COLOR:
835      return _NEW_FOG | _NEW_BUFFERS | _NEW_FRAG_CLAMP;
836   case STATE_FOG_PARAMS:
837   case STATE_FOG_PARAMS_OPTIMIZED:
838      return _NEW_FOG;
839
840   case STATE_CLIPPLANE:
841      return _NEW_TRANSFORM;
842
843   case STATE_POINT_SIZE:
844   case STATE_POINT_ATTENUATION:
845      return _NEW_POINT;
846
847   case STATE_MODELVIEW_MATRIX:
848   case STATE_MODELVIEW_MATRIX_INVERSE:
849   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
850   case STATE_MODELVIEW_MATRIX_INVTRANS:
851   case STATE_NORMAL_SCALE_EYESPACE:
852   case STATE_NORMAL_SCALE:
853      return _NEW_MODELVIEW;
854
855   case STATE_PROJECTION_MATRIX:
856   case STATE_PROJECTION_MATRIX_INVERSE:
857   case STATE_PROJECTION_MATRIX_TRANSPOSE:
858   case STATE_PROJECTION_MATRIX_INVTRANS:
859      return _NEW_PROJECTION;
860   case STATE_MVP_MATRIX:
861   case STATE_MVP_MATRIX_INVERSE:
862   case STATE_MVP_MATRIX_TRANSPOSE:
863   case STATE_MVP_MATRIX_INVTRANS:
864      return _NEW_MODELVIEW | _NEW_PROJECTION;
865   case STATE_TEXTURE_MATRIX:
866   case STATE_TEXTURE_MATRIX_INVERSE:
867   case STATE_TEXTURE_MATRIX_TRANSPOSE:
868   case STATE_TEXTURE_MATRIX_INVTRANS:
869      return _NEW_TEXTURE_MATRIX;
870   case STATE_PROGRAM_MATRIX:
871   case STATE_PROGRAM_MATRIX_INVERSE:
872   case STATE_PROGRAM_MATRIX_TRANSPOSE:
873   case STATE_PROGRAM_MATRIX_INVTRANS:
874      return _NEW_TRACK_MATRIX;
875
876   case STATE_NUM_SAMPLES:
877   case STATE_FB_SIZE:
878   case STATE_FB_WPOS_Y_TRANSFORM:
879      return _NEW_BUFFERS;
880
881   case STATE_FB_PNTC_Y_TRANSFORM:
882      return _NEW_BUFFERS | _NEW_POINT;
883
884   case STATE_DEPTH_RANGE:
885      return _NEW_VIEWPORT;
886
887   case STATE_FRAGMENT_PROGRAM_ENV:
888   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
889   case STATE_FRAGMENT_PROGRAM_LOCAL:
890   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
891   case STATE_VERTEX_PROGRAM_ENV:
892   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
893   case STATE_VERTEX_PROGRAM_LOCAL:
894   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
895      return _NEW_PROGRAM;
896
897   case STATE_CURRENT_ATTRIB:
898      return _NEW_CURRENT_ATTRIB;
899   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
900      return _NEW_CURRENT_ATTRIB | _NEW_LIGHT_STATE | _NEW_BUFFERS;
901
902   case STATE_POINT_SIZE_CLAMPED:
903      return _NEW_POINT | _NEW_MULTISAMPLE;
904
905   case STATE_PT_SCALE:
906   case STATE_PT_BIAS:
907      return _NEW_PIXEL;
908
909   case STATE_ADVANCED_BLENDING_MODE:
910   case STATE_ALPHA_REF:
911      return _NEW_COLOR;
912
913   case STATE_CLIP_INTERNAL:
914      return _NEW_TRANSFORM | _NEW_PROJECTION;
915
916   case STATE_TCS_PATCH_VERTICES_IN:
917   case STATE_TES_PATCH_VERTICES_IN:
918   case STATE_INTERNAL_DRIVER:
919      return 0; /* internal driver state */
920
921   case STATE_NOT_STATE_VAR:
922      return 0;
923
924   default:
925      _mesa_problem(NULL, "unexpected state[0] in make_state_flags()");
926      return 0;
927   }
928}
929
930
931static void
932append(char *dst, const char *src)
933{
934   while (*dst)
935      dst++;
936   while (*src)
937     *dst++ = *src++;
938   *dst = 0;
939}
940
941
942/**
943 * Convert token 'k' to a string, append it onto 'dst' string.
944 */
945static void
946append_token(char *dst, gl_state_index k)
947{
948   switch (k) {
949   case STATE_MATERIAL:
950      append(dst, "material");
951      break;
952   case STATE_LIGHT:
953      append(dst, "light");
954      break;
955   case STATE_LIGHT_ARRAY:
956      append(dst, "light.array");
957      break;
958   case STATE_LIGHT_ATTENUATION_ARRAY:
959      append(dst, "light.attenuation");
960      break;
961   case STATE_LIGHTMODEL_AMBIENT:
962      append(dst, "lightmodel.ambient");
963      break;
964   case STATE_LIGHTMODEL_SCENECOLOR:
965      break;
966   case STATE_LIGHTPROD:
967      append(dst, "lightprod");
968      break;
969   case STATE_LIGHTPROD_ARRAY_FRONT:
970      append(dst, "lightprod.array.front");
971      break;
972   case STATE_LIGHTPROD_ARRAY_BACK:
973      append(dst, "lightprod.array.back");
974      break;
975   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
976      append(dst, "lightprod.array.twoside");
977      break;
978   case STATE_TEXGEN:
979      append(dst, "texgen");
980      break;
981   case STATE_FOG_COLOR:
982      append(dst, "fog.color");
983      break;
984   case STATE_FOG_PARAMS:
985      append(dst, "fog.params");
986      break;
987   case STATE_CLIPPLANE:
988      append(dst, "clip");
989      break;
990   case STATE_POINT_SIZE:
991      append(dst, "point.size");
992      break;
993   case STATE_POINT_ATTENUATION:
994      append(dst, "point.attenuation");
995      break;
996   case STATE_MODELVIEW_MATRIX:
997      append(dst, "matrix.modelview.");
998      break;
999   case STATE_MODELVIEW_MATRIX_INVERSE:
1000      append(dst, "matrix.modelview.inverse.");
1001      break;
1002   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
1003      append(dst, "matrix.modelview.transpose.");
1004      break;
1005   case STATE_MODELVIEW_MATRIX_INVTRANS:
1006      append(dst, "matrix.modelview.invtrans.");
1007      break;
1008   case STATE_PROJECTION_MATRIX:
1009      append(dst, "matrix.projection.");
1010      break;
1011   case STATE_PROJECTION_MATRIX_INVERSE:
1012      append(dst, "matrix.projection.inverse.");
1013      break;
1014   case STATE_PROJECTION_MATRIX_TRANSPOSE:
1015      append(dst, "matrix.projection.transpose.");
1016      break;
1017   case STATE_PROJECTION_MATRIX_INVTRANS:
1018      append(dst, "matrix.projection.invtrans.");
1019      break;
1020   case STATE_MVP_MATRIX:
1021      append(dst, "matrix.mvp.");
1022      break;
1023   case STATE_MVP_MATRIX_INVERSE:
1024      append(dst, "matrix.mvp.inverse.");
1025      break;
1026   case STATE_MVP_MATRIX_TRANSPOSE:
1027      append(dst, "matrix.mvp.transpose.");
1028      break;
1029   case STATE_MVP_MATRIX_INVTRANS:
1030      append(dst, "matrix.mvp.invtrans.");
1031      break;
1032   case STATE_TEXTURE_MATRIX:
1033      append(dst, "matrix.texture");
1034      break;
1035   case STATE_TEXTURE_MATRIX_INVERSE:
1036      append(dst, "matrix.texture.inverse");
1037      break;
1038   case STATE_TEXTURE_MATRIX_TRANSPOSE:
1039      append(dst, "matrix.texture.transpose");
1040      break;
1041   case STATE_TEXTURE_MATRIX_INVTRANS:
1042      append(dst, "matrix.texture.invtrans");
1043      break;
1044   case STATE_PROGRAM_MATRIX:
1045      append(dst, "matrix.program");
1046      break;
1047   case STATE_PROGRAM_MATRIX_INVERSE:
1048      append(dst, "matrix.program.inverse");
1049      break;
1050   case STATE_PROGRAM_MATRIX_TRANSPOSE:
1051      append(dst, "matrix.program.transpose");
1052      break;
1053   case STATE_PROGRAM_MATRIX_INVTRANS:
1054      append(dst, "matrix.program.invtrans");
1055      break;
1056      break;
1057   case STATE_AMBIENT:
1058      append(dst, "ambient");
1059      break;
1060   case STATE_DIFFUSE:
1061      append(dst, "diffuse");
1062      break;
1063   case STATE_SPECULAR:
1064      append(dst, "specular");
1065      break;
1066   case STATE_EMISSION:
1067      append(dst, "emission");
1068      break;
1069   case STATE_SHININESS:
1070      append(dst, "shininess");
1071      break;
1072   case STATE_HALF_VECTOR:
1073      append(dst, "half");
1074      break;
1075   case STATE_POSITION:
1076      append(dst, "position");
1077      break;
1078   case STATE_ATTENUATION:
1079      append(dst, "attenuation");
1080      break;
1081   case STATE_SPOT_DIRECTION:
1082      append(dst, "spot.direction");
1083      break;
1084   case STATE_SPOT_CUTOFF:
1085      append(dst, "spot.cutoff");
1086      break;
1087   case STATE_TEXGEN_EYE_S:
1088      append(dst, "eye.s");
1089      break;
1090   case STATE_TEXGEN_EYE_T:
1091      append(dst, "eye.t");
1092      break;
1093   case STATE_TEXGEN_EYE_R:
1094      append(dst, "eye.r");
1095      break;
1096   case STATE_TEXGEN_EYE_Q:
1097      append(dst, "eye.q");
1098      break;
1099   case STATE_TEXGEN_OBJECT_S:
1100      append(dst, "object.s");
1101      break;
1102   case STATE_TEXGEN_OBJECT_T:
1103      append(dst, "object.t");
1104      break;
1105   case STATE_TEXGEN_OBJECT_R:
1106      append(dst, "object.r");
1107      break;
1108   case STATE_TEXGEN_OBJECT_Q:
1109      append(dst, "object.q");
1110      break;
1111   case STATE_TEXENV_COLOR:
1112      append(dst, "texenv");
1113      break;
1114   case STATE_NUM_SAMPLES:
1115      append(dst, "numsamples");
1116      break;
1117   case STATE_DEPTH_RANGE:
1118      append(dst, "depth.range");
1119      break;
1120   case STATE_VERTEX_PROGRAM_ENV:
1121   case STATE_FRAGMENT_PROGRAM_ENV:
1122      append(dst, "env");
1123      break;
1124   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
1125   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
1126      append(dst, "env.range");
1127      break;
1128   case STATE_VERTEX_PROGRAM_LOCAL:
1129   case STATE_FRAGMENT_PROGRAM_LOCAL:
1130      append(dst, "local");
1131      break;
1132   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
1133   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
1134      append(dst, "local.range");
1135      break;
1136   case STATE_CURRENT_ATTRIB:
1137      append(dst, "current");
1138      break;
1139   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
1140      append(dst, "currentAttribMaybeVPClamped");
1141      break;
1142   case STATE_NORMAL_SCALE_EYESPACE:
1143      append(dst, "normalScaleEyeSpace");
1144      break;
1145   case STATE_NORMAL_SCALE:
1146      append(dst, "normalScale");
1147      break;
1148   case STATE_FOG_PARAMS_OPTIMIZED:
1149      append(dst, "fogParamsOptimized");
1150      break;
1151   case STATE_POINT_SIZE_CLAMPED:
1152      append(dst, "pointSizeClamped");
1153      break;
1154   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
1155      append(dst, "lightSpotDirNormalized");
1156      break;
1157   case STATE_LIGHT_POSITION:
1158      append(dst, "light.position");
1159      break;
1160   case STATE_LIGHT_POSITION_ARRAY:
1161      append(dst, "light.position.array");
1162      break;
1163   case STATE_LIGHT_POSITION_NORMALIZED:
1164      append(dst, "light.position.normalized");
1165      break;
1166   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
1167      append(dst, "light.position.normalized.array");
1168      break;
1169   case STATE_LIGHT_HALF_VECTOR:
1170      append(dst, "lightHalfVector");
1171      break;
1172   case STATE_PT_SCALE:
1173      append(dst, "PTscale");
1174      break;
1175   case STATE_PT_BIAS:
1176      append(dst, "PTbias");
1177      break;
1178   case STATE_FB_SIZE:
1179      append(dst, "FbSize");
1180      break;
1181   case STATE_FB_WPOS_Y_TRANSFORM:
1182      append(dst, "FbWposYTransform");
1183      break;
1184   case STATE_FB_PNTC_Y_TRANSFORM:
1185      append(dst, "PntcYTransform");
1186      break;
1187   case STATE_ADVANCED_BLENDING_MODE:
1188      append(dst, "AdvancedBlendingMode");
1189      break;
1190   case STATE_ALPHA_REF:
1191      append(dst, "alphaRef");
1192      break;
1193   case STATE_CLIP_INTERNAL:
1194      append(dst, "clipInternal");
1195      break;
1196   default:
1197      /* probably STATE_INTERNAL_DRIVER+i (driver private state) */
1198      append(dst, "driverState");
1199   }
1200}
1201
1202static void
1203append_index(char *dst, GLint index, bool structure)
1204{
1205   char s[20];
1206   sprintf(s, "[%d]%s", index, structure ? "." : "");
1207   append(dst, s);
1208}
1209
1210/**
1211 * Make a string from the given state vector.
1212 * For example, return "state.matrix.texture[2].inverse".
1213 * Use free() to deallocate the string.
1214 */
1215char *
1216_mesa_program_state_string(const gl_state_index16 state[STATE_LENGTH])
1217{
1218   char str[1000] = "";
1219   char tmp[30];
1220
1221   append(str, "state.");
1222   append_token(str, state[0]);
1223
1224   switch (state[0]) {
1225   case STATE_LIGHT:
1226      append_index(str, state[1], true); /* light number [i]. */
1227      append_token(str, state[2]); /* coefficients */
1228      break;
1229   case STATE_LIGHTMODEL_AMBIENT:
1230      break;
1231   case STATE_LIGHTMODEL_SCENECOLOR:
1232      if (state[1] == 0) {
1233         append(str, "lightmodel.front.scenecolor");
1234      }
1235      else {
1236         append(str, "lightmodel.back.scenecolor");
1237      }
1238      break;
1239   case STATE_LIGHTPROD:
1240      append_index(str, state[1], false); /* light number [i] */
1241      append_index(str, state[2], false);
1242      break;
1243   case STATE_TEXGEN:
1244      append_index(str, state[1], true); /* tex unit [i] */
1245      append_token(str, state[2]); /* plane coef */
1246      break;
1247   case STATE_TEXENV_COLOR:
1248      append_index(str, state[1], true); /* tex unit [i] */
1249      append(str, "color");
1250      break;
1251   case STATE_CLIPPLANE:
1252      append_index(str, state[1], true); /* plane [i] */
1253      append(str, "plane");
1254      break;
1255   case STATE_MODELVIEW_MATRIX:
1256   case STATE_MODELVIEW_MATRIX_INVERSE:
1257   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
1258   case STATE_MODELVIEW_MATRIX_INVTRANS:
1259   case STATE_PROJECTION_MATRIX:
1260   case STATE_PROJECTION_MATRIX_INVERSE:
1261   case STATE_PROJECTION_MATRIX_TRANSPOSE:
1262   case STATE_PROJECTION_MATRIX_INVTRANS:
1263   case STATE_MVP_MATRIX:
1264   case STATE_MVP_MATRIX_INVERSE:
1265   case STATE_MVP_MATRIX_TRANSPOSE:
1266   case STATE_MVP_MATRIX_INVTRANS:
1267   case STATE_TEXTURE_MATRIX:
1268   case STATE_TEXTURE_MATRIX_INVERSE:
1269   case STATE_TEXTURE_MATRIX_TRANSPOSE:
1270   case STATE_TEXTURE_MATRIX_INVTRANS:
1271   case STATE_PROGRAM_MATRIX:
1272   case STATE_PROGRAM_MATRIX_INVERSE:
1273   case STATE_PROGRAM_MATRIX_TRANSPOSE:
1274   case STATE_PROGRAM_MATRIX_INVTRANS:
1275      {
1276         /* state[0] = modelview, projection, texture, etc. */
1277         /* state[1] = which texture matrix or program matrix */
1278         /* state[2] = first row to fetch */
1279         /* state[3] = last row to fetch */
1280         const gl_state_index mat = state[0];
1281         const GLuint index = (GLuint) state[1];
1282         const GLuint firstRow = (GLuint) state[2];
1283         const GLuint lastRow = (GLuint) state[3];
1284         if (index ||
1285             (mat >= STATE_TEXTURE_MATRIX &&
1286              mat <= STATE_PROGRAM_MATRIX_INVTRANS))
1287            append_index(str, index, true);
1288         if (firstRow == lastRow)
1289            sprintf(tmp, "row[%d]", firstRow);
1290         else
1291            sprintf(tmp, "row[%d..%d]", firstRow, lastRow);
1292         append(str, tmp);
1293      }
1294      break;
1295   case STATE_LIGHT_ARRAY:
1296   case STATE_LIGHT_ATTENUATION_ARRAY:
1297   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
1298   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
1299   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
1300   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
1301   case STATE_LIGHTPROD_ARRAY_FRONT:
1302   case STATE_LIGHTPROD_ARRAY_BACK:
1303   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
1304   case STATE_LIGHT_POSITION_ARRAY:
1305   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
1306      sprintf(tmp, "[%d..%d]", state[1], state[1] + state[2] - 1);
1307      append(str, tmp);
1308      break;
1309   case STATE_MATERIAL:
1310   case STATE_FRAGMENT_PROGRAM_ENV:
1311   case STATE_FRAGMENT_PROGRAM_LOCAL:
1312   case STATE_VERTEX_PROGRAM_ENV:
1313   case STATE_VERTEX_PROGRAM_LOCAL:
1314   case STATE_CURRENT_ATTRIB:
1315   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
1316   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
1317   case STATE_LIGHT_POSITION:
1318   case STATE_LIGHT_POSITION_NORMALIZED:
1319   case STATE_LIGHT_HALF_VECTOR:
1320   case STATE_CLIP_INTERNAL:
1321      append_index(str, state[1], false);
1322      break;
1323   case STATE_POINT_SIZE:
1324   case STATE_POINT_ATTENUATION:
1325   case STATE_FOG_PARAMS:
1326   case STATE_FOG_COLOR:
1327   case STATE_NUM_SAMPLES:
1328   case STATE_DEPTH_RANGE:
1329   case STATE_NORMAL_SCALE_EYESPACE:
1330   case STATE_NORMAL_SCALE:
1331   case STATE_FOG_PARAMS_OPTIMIZED:
1332   case STATE_POINT_SIZE_CLAMPED:
1333   case STATE_PT_SCALE:
1334   case STATE_PT_BIAS:
1335   case STATE_FB_SIZE:
1336   case STATE_FB_WPOS_Y_TRANSFORM:
1337   case STATE_TCS_PATCH_VERTICES_IN:
1338   case STATE_TES_PATCH_VERTICES_IN:
1339   case STATE_ADVANCED_BLENDING_MODE:
1340   case STATE_ALPHA_REF:
1341      break;
1342   case STATE_NOT_STATE_VAR:
1343      append(str, "not_state");
1344      break;
1345   default:
1346      _mesa_problem(NULL, "Invalid state in _mesa_program_state_string");
1347      break;
1348   }
1349
1350   return strdup(str);
1351}
1352
1353
1354/**
1355 * Loop over all the parameters in a parameter list.  If the parameter
1356 * is a GL state reference, look up the current value of that state
1357 * variable and put it into the parameter's Value[4] array.
1358 * Other parameter types never change or are explicitly set by the user
1359 * with glUniform() or glProgramParameter(), etc.
1360 * This would be called at glBegin time.
1361 */
1362void
1363_mesa_load_state_parameters(struct gl_context *ctx,
1364                            struct gl_program_parameter_list *paramList)
1365{
1366   if (!paramList)
1367      return;
1368
1369   int last = paramList->LastStateVarIndex;
1370
1371   for (int i = paramList->FirstStateVarIndex; i <= last; i++) {
1372      unsigned pvo = paramList->Parameters[i].ValueOffset;
1373      fetch_state(ctx, paramList->Parameters[i].StateIndexes,
1374                  paramList->ParameterValues + pvo);
1375   }
1376}
1377
1378void
1379_mesa_upload_state_parameters(struct gl_context *ctx,
1380                              struct gl_program_parameter_list *paramList,
1381                              uint32_t *dst)
1382{
1383   int last = paramList->LastStateVarIndex;
1384
1385   for (int i = paramList->FirstStateVarIndex; i <= last; i++) {
1386      unsigned pvo = paramList->Parameters[i].ValueOffset;
1387      fetch_state(ctx, paramList->Parameters[i].StateIndexes,
1388                  (gl_constant_value*)(dst + pvo));
1389   }
1390}
1391
1392/* Merge consecutive state vars into one for the state vars that allow
1393 * multiple vec4s.
1394 *
1395 * This should be done after shader compilation, so that drivers don't
1396 * have to deal with multi-slot state parameters in their backends.
1397 * It's only meant to optimize _mesa_load/upload_state_parameters.
1398 */
1399void
1400_mesa_optimize_state_parameters(struct gl_constants *consts,
1401                                struct gl_program_parameter_list *list)
1402{
1403   for (int first_param = list->FirstStateVarIndex;
1404        first_param < (int)list->NumParameters; first_param++) {
1405      int last_param = first_param;
1406      int param_diff = 0;
1407
1408      switch (list->Parameters[first_param].StateIndexes[0]) {
1409      case STATE_MODELVIEW_MATRIX:
1410      case STATE_MODELVIEW_MATRIX_INVERSE:
1411      case STATE_MODELVIEW_MATRIX_TRANSPOSE:
1412      case STATE_MODELVIEW_MATRIX_INVTRANS:
1413      case STATE_PROJECTION_MATRIX:
1414      case STATE_PROJECTION_MATRIX_INVERSE:
1415      case STATE_PROJECTION_MATRIX_TRANSPOSE:
1416      case STATE_PROJECTION_MATRIX_INVTRANS:
1417      case STATE_MVP_MATRIX:
1418      case STATE_MVP_MATRIX_INVERSE:
1419      case STATE_MVP_MATRIX_TRANSPOSE:
1420      case STATE_MVP_MATRIX_INVTRANS:
1421      case STATE_TEXTURE_MATRIX:
1422      case STATE_TEXTURE_MATRIX_INVERSE:
1423      case STATE_TEXTURE_MATRIX_TRANSPOSE:
1424      case STATE_TEXTURE_MATRIX_INVTRANS:
1425      case STATE_PROGRAM_MATRIX:
1426      case STATE_PROGRAM_MATRIX_INVERSE:
1427      case STATE_PROGRAM_MATRIX_TRANSPOSE:
1428      case STATE_PROGRAM_MATRIX_INVTRANS:
1429         /* Skip unaligned state vars. */
1430         if (list->Parameters[first_param].Size % 4)
1431            break;
1432
1433         /* Search for adjacent state vars that refer to adjacent rows. */
1434         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
1435            if (list->Parameters[i].StateIndexes[0] ==
1436                list->Parameters[i - 1].StateIndexes[0] &&
1437                list->Parameters[i].StateIndexes[1] ==
1438                list->Parameters[i - 1].StateIndexes[1] &&
1439                list->Parameters[i].StateIndexes[2] ==         /* FirstRow */
1440                list->Parameters[i - 1].StateIndexes[3] + 1 && /* LastRow + 1 */
1441                list->Parameters[i].Size == 4) {
1442               last_param = i;
1443               continue;
1444            }
1445            break; /* The adjacent state var is incompatible. */
1446         }
1447         if (last_param > first_param) {
1448            int first_vec = list->Parameters[first_param].StateIndexes[2];
1449            int last_vec = list->Parameters[last_param].StateIndexes[3];
1450
1451            assert(first_vec < last_vec);
1452            assert(last_vec - first_vec == last_param - first_param);
1453
1454            /* Update LastRow. */
1455            list->Parameters[first_param].StateIndexes[3] = last_vec;
1456            list->Parameters[first_param].Size = (last_vec - first_vec + 1) * 4;
1457
1458            param_diff = last_param - first_param;
1459         }
1460         break;
1461
1462      case STATE_LIGHT:
1463         /* Skip trimmed state vars. (this shouldn't occur though) */
1464         if (list->Parameters[first_param].Size !=
1465             _mesa_program_state_value_size(list->Parameters[first_param].StateIndexes))
1466            break;
1467
1468         /* Search for light attributes that are adjacent in memory. */
1469         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
1470            if (list->Parameters[i].StateIndexes[0] == STATE_LIGHT &&
1471                /* Consecutive attributes of the same light: */
1472                ((list->Parameters[i].StateIndexes[1] ==
1473                  list->Parameters[i - 1].StateIndexes[1] &&
1474                  list->Parameters[i].StateIndexes[2] ==
1475                  list->Parameters[i - 1].StateIndexes[2] + 1) ||
1476                 /* Consecutive attributes between 2 lights: */
1477                 /* SPOT_CUTOFF should have only 1 component, which isn't true
1478                  * with unpacked uniform storage. */
1479                 (consts->PackedDriverUniformStorage &&
1480                  list->Parameters[i].StateIndexes[1] ==
1481                  list->Parameters[i - 1].StateIndexes[1] + 1 &&
1482                  list->Parameters[i].StateIndexes[2] == STATE_AMBIENT &&
1483                  list->Parameters[i - 1].StateIndexes[2] == STATE_SPOT_CUTOFF))) {
1484               last_param = i;
1485               continue;
1486            }
1487            break; /* The adjacent state var is incompatible. */
1488         }
1489         if (last_param > first_param) {
1490            /* Convert the state var to STATE_LIGHT_ARRAY. */
1491            list->Parameters[first_param].StateIndexes[0] = STATE_LIGHT_ARRAY;
1492            /* Set the offset in floats. */
1493            list->Parameters[first_param].StateIndexes[1] =
1494               list->Parameters[first_param].StateIndexes[1] * /* light index */
1495               sizeof(struct gl_light_uniforms) / 4 +
1496               (list->Parameters[first_param].StateIndexes[2] - STATE_AMBIENT) * 4;
1497
1498            /* Set the real size in floats that we will upload (memcpy). */
1499            list->Parameters[first_param].StateIndexes[2] =
1500               _mesa_program_state_value_size(list->Parameters[last_param].StateIndexes) +
1501               list->Parameters[last_param].ValueOffset -
1502               list->Parameters[first_param].ValueOffset;
1503
1504            /* Set the allocated size, which can be aligned to 4 components. */
1505            list->Parameters[first_param].Size =
1506               list->Parameters[last_param].Size +
1507               list->Parameters[last_param].ValueOffset -
1508               list->Parameters[first_param].ValueOffset;
1509
1510            param_diff = last_param - first_param;
1511            break; /* all done */
1512         }
1513
1514         /* We were not able to convert light attributes to STATE_LIGHT_ARRAY.
1515          * Another occuring pattern is light attentuation vectors placed back
1516          * to back. Find them.
1517          */
1518         if (list->Parameters[first_param].StateIndexes[2] == STATE_ATTENUATION) {
1519            for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
1520               if (list->Parameters[i].StateIndexes[0] == STATE_LIGHT &&
1521                   /* Consecutive light: */
1522                   list->Parameters[i].StateIndexes[1] ==
1523                   list->Parameters[i - 1].StateIndexes[1] + 1 &&
1524                   /* Same attribute: */
1525                   list->Parameters[i].StateIndexes[2] ==
1526                   list->Parameters[i - 1].StateIndexes[2]) {
1527                  last_param = i;
1528                  continue;
1529               }
1530               break; /* The adjacent state var is incompatible. */
1531            }
1532            if (last_param > first_param) {
1533               param_diff = last_param - first_param;
1534
1535               /* Convert the state var to STATE_LIGHT_ATTENUATION_ARRAY. */
1536               list->Parameters[first_param].StateIndexes[0] =
1537                  STATE_LIGHT_ATTENUATION_ARRAY;
1538               /* Keep the light index the same. */
1539               /* Set the number of lights. */
1540               unsigned size = param_diff + 1;
1541               list->Parameters[first_param].StateIndexes[2] = size;
1542               list->Parameters[first_param].Size = size * 4;
1543               break; /* all done */
1544            }
1545         }
1546         break;
1547
1548      case STATE_VERTEX_PROGRAM_ENV:
1549      case STATE_VERTEX_PROGRAM_LOCAL:
1550      case STATE_FRAGMENT_PROGRAM_ENV:
1551      case STATE_FRAGMENT_PROGRAM_LOCAL:
1552         if (list->Parameters[first_param].Size != 4)
1553            break;
1554
1555         /* Search for adjacent mergeable state vars. */
1556         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
1557            if (list->Parameters[i].StateIndexes[0] ==
1558                list->Parameters[i - 1].StateIndexes[0] &&
1559                list->Parameters[i].StateIndexes[1] ==
1560                list->Parameters[i - 1].StateIndexes[1] + 1 &&
1561                list->Parameters[i].Size == 4) {
1562               last_param = i;
1563               continue;
1564            }
1565            break; /* The adjacent state var is incompatible. */
1566         }
1567         if (last_param > first_param) {
1568            /* Set STATE_xxx_RANGE. */
1569            STATIC_ASSERT(STATE_VERTEX_PROGRAM_ENV + 1 ==
1570                          STATE_VERTEX_PROGRAM_ENV_ARRAY);
1571            STATIC_ASSERT(STATE_VERTEX_PROGRAM_LOCAL + 1 ==
1572                          STATE_VERTEX_PROGRAM_LOCAL_ARRAY);
1573            STATIC_ASSERT(STATE_FRAGMENT_PROGRAM_ENV + 1 ==
1574                          STATE_FRAGMENT_PROGRAM_ENV_ARRAY);
1575            STATIC_ASSERT(STATE_FRAGMENT_PROGRAM_LOCAL + 1 ==
1576                          STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY);
1577            list->Parameters[first_param].StateIndexes[0]++;
1578
1579            param_diff = last_param - first_param;
1580
1581            /* Set the size. */
1582            unsigned size = param_diff + 1;
1583            list->Parameters[first_param].StateIndexes[2] = size;
1584            list->Parameters[first_param].Size = size * 4;
1585         }
1586         break;
1587
1588      case STATE_LIGHTPROD: {
1589         if (list->Parameters[first_param].Size != 4)
1590            break;
1591
1592         gl_state_index16 state = STATE_NOT_STATE_VAR;
1593         unsigned num_lights = 0;
1594
1595         for (unsigned state_iter = STATE_LIGHTPROD_ARRAY_FRONT;
1596              state_iter <= STATE_LIGHTPROD_ARRAY_TWOSIDE; state_iter++) {
1597            unsigned num_attribs, base_attrib, attrib_incr;
1598
1599            if (state_iter == STATE_LIGHTPROD_ARRAY_FRONT)  {
1600               num_attribs = 3;
1601               base_attrib = MAT_ATTRIB_FRONT_AMBIENT;
1602               attrib_incr = 2;
1603            } else if (state_iter == STATE_LIGHTPROD_ARRAY_BACK) {
1604               num_attribs = 3;
1605               base_attrib = MAT_ATTRIB_BACK_AMBIENT;
1606               attrib_incr = 2;
1607            } else if (state_iter == STATE_LIGHTPROD_ARRAY_TWOSIDE) {
1608               num_attribs = 6;
1609               base_attrib = MAT_ATTRIB_FRONT_AMBIENT;
1610               attrib_incr = 1;
1611            }
1612
1613            /* Find all attributes for one light. */
1614            while (first_param + (num_lights + 1) * num_attribs <=
1615                   list->NumParameters &&
1616                   (state == STATE_NOT_STATE_VAR || state == state_iter)) {
1617               unsigned i = 0, base = first_param + num_lights * num_attribs;
1618
1619               /* Consecutive light indices: */
1620               if (list->Parameters[first_param].StateIndexes[1] + num_lights ==
1621                   list->Parameters[base].StateIndexes[1]) {
1622                  for (i = 0; i < num_attribs; i++) {
1623                     if (list->Parameters[base + i].StateIndexes[0] ==
1624                         STATE_LIGHTPROD &&
1625                         list->Parameters[base + i].Size == 4 &&
1626                         /* Equal light indices: */
1627                         list->Parameters[base + i].StateIndexes[1] ==
1628                         list->Parameters[base + 0].StateIndexes[1] &&
1629                         /* Consecutive attributes: */
1630                         list->Parameters[base + i].StateIndexes[2] ==
1631                         base_attrib + i * attrib_incr)
1632                        continue;
1633                     break;
1634                  }
1635               }
1636               if (i == num_attribs) {
1637                  /* Accept all parameters for merging. */
1638                  state = state_iter;
1639                  last_param = base + num_attribs - 1;
1640                  num_lights++;
1641               } else {
1642                  break;
1643               }
1644            }
1645         }
1646
1647         if (last_param > first_param) {
1648            param_diff = last_param - first_param;
1649
1650            list->Parameters[first_param].StateIndexes[0] = state;
1651            list->Parameters[first_param].StateIndexes[2] = num_lights;
1652            list->Parameters[first_param].Size = (param_diff + 1) * 4;
1653         }
1654         break;
1655      }
1656
1657      case STATE_LIGHT_POSITION:
1658      case STATE_LIGHT_POSITION_NORMALIZED:
1659         if (list->Parameters[first_param].Size != 4)
1660            break;
1661
1662         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
1663            if (list->Parameters[i].StateIndexes[0] ==
1664                list->Parameters[i - 1].StateIndexes[0] &&
1665                /* Consecutive light: */
1666                list->Parameters[i].StateIndexes[1] ==
1667                list->Parameters[i - 1].StateIndexes[1] + 1) {
1668               last_param = i;
1669               continue;
1670            }
1671            break; /* The adjacent state var is incompatible. */
1672         }
1673         if (last_param > first_param) {
1674            param_diff = last_param - first_param;
1675
1676            /* Convert the state var to STATE_LIGHT_POSITION_*ARRAY. */
1677            STATIC_ASSERT(STATE_LIGHT_POSITION + 1 ==
1678                          STATE_LIGHT_POSITION_ARRAY);
1679            STATIC_ASSERT(STATE_LIGHT_POSITION_NORMALIZED + 1 ==
1680                          STATE_LIGHT_POSITION_NORMALIZED_ARRAY);
1681            list->Parameters[first_param].StateIndexes[0]++;
1682            /* Keep the light index the same. */
1683            unsigned size = param_diff + 1;
1684            /* Set the number of lights. */
1685            list->Parameters[first_param].StateIndexes[2] = size;
1686            list->Parameters[first_param].Size = size * 4;
1687         }
1688      }
1689
1690      if (param_diff) {
1691         /* Update the name. */
1692         free((void*)list->Parameters[first_param].Name);
1693         list->Parameters[first_param].Name =
1694            _mesa_program_state_string(list->Parameters[first_param].StateIndexes);
1695
1696         /* Free names that we are going to overwrite. */
1697         for (int i = first_param + 1; i <= last_param; i++)
1698            free((char*)list->Parameters[i].Name);
1699
1700         /* Remove the merged state vars. */
1701         if (last_param + 1 < list->NumParameters) {
1702            memmove(&list->Parameters[first_param + 1],
1703                    &list->Parameters[last_param + 1],
1704                    sizeof(list->Parameters[0]) *
1705                    (list->NumParameters - last_param - 1));
1706         }
1707         list->NumParameters -= param_diff;
1708      }
1709   }
1710
1711   _mesa_recompute_parameter_bounds(list);
1712}
1713