13464ebd5Sriastradh/*
23464ebd5Sriastradh * Mesa 3-D graphics library
33464ebd5Sriastradh *
43464ebd5Sriastradh * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
53464ebd5Sriastradh *
63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
73464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"),
83464ebd5Sriastradh * to deal in the Software without restriction, including without limitation
93464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
103464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
113464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions:
123464ebd5Sriastradh *
133464ebd5Sriastradh * The above copyright notice and this permission notice shall be included
143464ebd5Sriastradh * in all copies or substantial portions of the Software.
153464ebd5Sriastradh *
163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
173464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh */
243464ebd5Sriastradh
253464ebd5Sriastradh/**
263464ebd5Sriastradh * \file prog_statevars.c
273464ebd5Sriastradh * Program state variable management.
283464ebd5Sriastradh * \author Brian Paul
293464ebd5Sriastradh */
303464ebd5Sriastradh
313464ebd5Sriastradh
3201e04c3fSmrg#include <stdio.h>
337ec681f3Smrg#include <stddef.h>
343464ebd5Sriastradh#include "main/glheader.h"
353464ebd5Sriastradh#include "main/context.h"
36af69d88dSmrg#include "main/blend.h"
377ec681f3Smrg
383464ebd5Sriastradh#include "main/macros.h"
393464ebd5Sriastradh#include "main/mtypes.h"
40af69d88dSmrg#include "main/fbobject.h"
413464ebd5Sriastradh#include "prog_statevars.h"
423464ebd5Sriastradh#include "prog_parameter.h"
43af69d88dSmrg#include "main/samplerobj.h"
4401e04c3fSmrg#include "main/framebuffer.h"
4501e04c3fSmrg
4601e04c3fSmrg
4701e04c3fSmrg#define ONE_DIV_SQRT_LN2 (1.201122408786449815)
483464ebd5Sriastradh
497ec681f3Smrgstatic ALWAYS_INLINE void
507ec681f3Smrgcopy_matrix(float *value, const float *m, unsigned firstRow, unsigned lastRow)
517ec681f3Smrg{
527ec681f3Smrg   unsigned i, row;
537ec681f3Smrg
547ec681f3Smrg   assert(firstRow < 4);
557ec681f3Smrg   assert(lastRow < 4);
567ec681f3Smrg
577ec681f3Smrg   for (i = 0, row = firstRow; row <= lastRow; row++) {
587ec681f3Smrg      value[i++] = m[row + 0];
597ec681f3Smrg      value[i++] = m[row + 4];
607ec681f3Smrg      value[i++] = m[row + 8];
617ec681f3Smrg      value[i++] = m[row + 12];
627ec681f3Smrg   }
637ec681f3Smrg}
647ec681f3Smrg
657ec681f3Smrgstatic ALWAYS_INLINE void
667ec681f3Smrgcopy_matrix_transposed(float *value, const float *m, unsigned firstRow, unsigned lastRow)
677ec681f3Smrg{
687ec681f3Smrg   assert(firstRow < 4);
697ec681f3Smrg   assert(lastRow < 4);
707ec681f3Smrg
717ec681f3Smrg   memcpy(value, &m[firstRow * 4],
727ec681f3Smrg          (lastRow - firstRow + 1) * 4 * sizeof(GLfloat));
737ec681f3Smrg}
743464ebd5Sriastradh
753464ebd5Sriastradh/**
763464ebd5Sriastradh * Use the list of tokens in the state[] array to find global GL state
773464ebd5Sriastradh * and return it in <value>.  Usually, four values are returned in <value>
783464ebd5Sriastradh * but matrix queries may return as many as 16 values.
793464ebd5Sriastradh * This function is used for ARB vertex/fragment programs.
803464ebd5Sriastradh * The program parser will produce the state[] values.
813464ebd5Sriastradh */
823464ebd5Sriastradhstatic void
837ec681f3Smrgfetch_state(struct gl_context *ctx, const gl_state_index16 state[],
847ec681f3Smrg            gl_constant_value *val)
853464ebd5Sriastradh{
8601e04c3fSmrg   GLfloat *value = &val->f;
8701e04c3fSmrg
883464ebd5Sriastradh   switch (state[0]) {
893464ebd5Sriastradh   case STATE_MATERIAL:
903464ebd5Sriastradh      {
917ec681f3Smrg         /* state[1] is MAT_ATTRIB_FRONT_* */
927ec681f3Smrg         const GLuint index = (GLuint) state[1];
933464ebd5Sriastradh         const struct gl_material *mat = &ctx->Light.Material;
947ec681f3Smrg         assert(index >= MAT_ATTRIB_FRONT_AMBIENT &&
957ec681f3Smrg                index <= MAT_ATTRIB_BACK_SHININESS);
967ec681f3Smrg         if (index >= MAT_ATTRIB_FRONT_SHININESS) {
977ec681f3Smrg            value[0] = mat->Attrib[index][0];
983464ebd5Sriastradh            value[1] = 0.0F;
993464ebd5Sriastradh            value[2] = 0.0F;
1003464ebd5Sriastradh            value[3] = 1.0F;
1017ec681f3Smrg         } else {
1027ec681f3Smrg            COPY_4V(value, mat->Attrib[index]);
1033464ebd5Sriastradh         }
1047ec681f3Smrg         return;
1053464ebd5Sriastradh      }
1063464ebd5Sriastradh   case STATE_LIGHT:
1073464ebd5Sriastradh      {
1083464ebd5Sriastradh         /* state[1] is the light number */
1093464ebd5Sriastradh         const GLuint ln = (GLuint) state[1];
1103464ebd5Sriastradh         /* state[2] is the light attribute */
1117ec681f3Smrg         const unsigned index = state[2] - STATE_AMBIENT;
1127ec681f3Smrg         assert(index < 8);
1137ec681f3Smrg         if (index != STATE_SPOT_CUTOFF)
1147ec681f3Smrg            COPY_4V(value, (float*)&ctx->Light.LightSource[ln] + index * 4);
1157ec681f3Smrg         else
1167ec681f3Smrg            value[0] = ctx->Light.LightSource[ln].SpotCutoff;
1177ec681f3Smrg         return;
1183464ebd5Sriastradh      }
1197ec681f3Smrg   case STATE_LIGHT_ARRAY: {
1207ec681f3Smrg      /* This must be exact because it must match the gl_LightSource layout
1217ec681f3Smrg       * in GLSL.
1227ec681f3Smrg       */
1237ec681f3Smrg      STATIC_ASSERT(sizeof(struct gl_light_uniforms) == 29 * 4);
1247ec681f3Smrg      STATIC_ASSERT(ARRAY_SIZE(ctx->Light.LightSourceData) == 29 * MAX_LIGHTS);
1257ec681f3Smrg      /* state[1] is the index of the first value */
1267ec681f3Smrg      /* state[2] is the number of values */
1277ec681f3Smrg      assert(state[1] + state[2] <= ARRAY_SIZE(ctx->Light.LightSourceData));
1287ec681f3Smrg      memcpy(value, &ctx->Light.LightSourceData[state[1]],
1297ec681f3Smrg             state[2] * sizeof(float));
1307ec681f3Smrg      return;
1317ec681f3Smrg   }
1327ec681f3Smrg   case STATE_LIGHT_ATTENUATION_ARRAY: {
1337ec681f3Smrg      const unsigned first = state[1];
1347ec681f3Smrg      const unsigned num_lights = state[2];
1357ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
1367ec681f3Smrg         COPY_4V(value,
1377ec681f3Smrg                 &ctx->Light.LightSource[first + i].ConstantAttenuation);
1387ec681f3Smrg         value += 4;
1397ec681f3Smrg      }
1407ec681f3Smrg      return;
1417ec681f3Smrg   }
1423464ebd5Sriastradh   case STATE_LIGHTMODEL_AMBIENT:
1433464ebd5Sriastradh      COPY_4V(value, ctx->Light.Model.Ambient);
1443464ebd5Sriastradh      return;
1453464ebd5Sriastradh   case STATE_LIGHTMODEL_SCENECOLOR:
1463464ebd5Sriastradh      if (state[1] == 0) {
1473464ebd5Sriastradh         /* front */
1483464ebd5Sriastradh         GLint i;
1493464ebd5Sriastradh         for (i = 0; i < 3; i++) {
1503464ebd5Sriastradh            value[i] = ctx->Light.Model.Ambient[i]
1513464ebd5Sriastradh               * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
1523464ebd5Sriastradh               + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
1533464ebd5Sriastradh         }
1543464ebd5Sriastradh	 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
1553464ebd5Sriastradh      }
1563464ebd5Sriastradh      else {
1573464ebd5Sriastradh         /* back */
1583464ebd5Sriastradh         GLint i;
1593464ebd5Sriastradh         for (i = 0; i < 3; i++) {
1603464ebd5Sriastradh            value[i] = ctx->Light.Model.Ambient[i]
1613464ebd5Sriastradh               * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
1623464ebd5Sriastradh               + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
1633464ebd5Sriastradh         }
1643464ebd5Sriastradh	 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
1653464ebd5Sriastradh      }
1663464ebd5Sriastradh      return;
1673464ebd5Sriastradh   case STATE_LIGHTPROD:
1683464ebd5Sriastradh      {
1693464ebd5Sriastradh         const GLuint ln = (GLuint) state[1];
1707ec681f3Smrg         const GLuint index = (GLuint) state[2];
1717ec681f3Smrg         const GLuint attr = (index / 2) * 4;
1727ec681f3Smrg         assert(index >= MAT_ATTRIB_FRONT_AMBIENT &&
1737ec681f3Smrg                index <= MAT_ATTRIB_BACK_SPECULAR);
1747ec681f3Smrg         for (int i = 0; i < 3; i++) {
1757ec681f3Smrg            /* We want attr to access out of bounds into the following Diffuse
1767ec681f3Smrg             * and Specular fields. This is guaranteed to work because
1777ec681f3Smrg             * STATE_LIGHT and STATE_LIGHT_ARRAY also rely on this memory
1787ec681f3Smrg             * layout.
1797ec681f3Smrg             */
1807ec681f3Smrg            STATIC_ASSERT(offsetof(struct gl_light_uniforms, Ambient) + 16 ==
1817ec681f3Smrg                          offsetof(struct gl_light_uniforms, Diffuse));
1827ec681f3Smrg            STATIC_ASSERT(offsetof(struct gl_light_uniforms, Diffuse) + 16 ==
1837ec681f3Smrg                          offsetof(struct gl_light_uniforms, Specular));
1847ec681f3Smrg            value[i] = ctx->Light.LightSource[ln].Ambient[attr + i] *
1857ec681f3Smrg                       ctx->Light.Material.Attrib[index][i];
1867ec681f3Smrg         }
1877ec681f3Smrg         /* [3] = material alpha */
1887ec681f3Smrg         value[3] = ctx->Light.Material.Attrib[index][3];
1897ec681f3Smrg         return;
1907ec681f3Smrg      }
1917ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_FRONT: {
1927ec681f3Smrg      const unsigned first_light = state[1];
1937ec681f3Smrg      const unsigned num_lights = state[2];
1947ec681f3Smrg
1957ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
1967ec681f3Smrg         unsigned light = first_light + i;
1977ec681f3Smrg
1987ec681f3Smrg         for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT;
1997ec681f3Smrg              attrib <= MAT_ATTRIB_FRONT_SPECULAR; attrib += 2) {
2007ec681f3Smrg            for (int chan = 0; chan < 3; chan++) {
2017ec681f3Smrg               /* We want offset to access out of bounds into the following
2027ec681f3Smrg                * Diffuse and Specular fields. This is guaranteed to work
2037ec681f3Smrg                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
2047ec681f3Smrg                * on this memory layout.
2057ec681f3Smrg                */
2067ec681f3Smrg               unsigned offset = (attrib / 2) * 4 + chan;
2077ec681f3Smrg               *value++ =
2087ec681f3Smrg                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
2097ec681f3Smrg                  ctx->Light.Material.Attrib[attrib][chan];
2107ec681f3Smrg            }
2117ec681f3Smrg            /* [3] = material alpha */
2127ec681f3Smrg            *value++ = ctx->Light.Material.Attrib[attrib][3];
2133464ebd5Sriastradh         }
2143464ebd5Sriastradh      }
2157ec681f3Smrg      return;
2167ec681f3Smrg   }
2177ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_BACK: {
2187ec681f3Smrg      const unsigned first_light = state[1];
2197ec681f3Smrg      const unsigned num_lights = state[2];
2207ec681f3Smrg
2217ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
2227ec681f3Smrg         unsigned light = first_light + i;
2237ec681f3Smrg
2247ec681f3Smrg         for (unsigned attrib = MAT_ATTRIB_BACK_AMBIENT;
2257ec681f3Smrg              attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib += 2) {
2267ec681f3Smrg            for (int chan = 0; chan < 3; chan++) {
2277ec681f3Smrg               /* We want offset to access out of bounds into the following
2287ec681f3Smrg                * Diffuse and Specular fields. This is guaranteed to work
2297ec681f3Smrg                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
2307ec681f3Smrg                * on this memory layout.
2317ec681f3Smrg                */
2327ec681f3Smrg               unsigned offset = (attrib / 2) * 4 + chan;
2337ec681f3Smrg               *value++ =
2347ec681f3Smrg                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
2357ec681f3Smrg                  ctx->Light.Material.Attrib[attrib][chan];
2367ec681f3Smrg            }
2377ec681f3Smrg            /* [3] = material alpha */
2387ec681f3Smrg            *value++ = ctx->Light.Material.Attrib[attrib][3];
2397ec681f3Smrg         }
2407ec681f3Smrg      }
2417ec681f3Smrg      return;
2427ec681f3Smrg   }
2437ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_TWOSIDE: {
2447ec681f3Smrg      const unsigned first_light = state[1];
2457ec681f3Smrg      const unsigned num_lights = state[2];
2467ec681f3Smrg
2477ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
2487ec681f3Smrg         unsigned light = first_light + i;
2497ec681f3Smrg
2507ec681f3Smrg         for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT;
2517ec681f3Smrg              attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib++) {
2527ec681f3Smrg            for (int chan = 0; chan < 3; chan++) {
2537ec681f3Smrg               /* We want offset to access out of bounds into the following
2547ec681f3Smrg                * Diffuse and Specular fields. This is guaranteed to work
2557ec681f3Smrg                * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely
2567ec681f3Smrg                * on this memory layout.
2577ec681f3Smrg                */
2587ec681f3Smrg               unsigned offset = (attrib / 2) * 4 + chan;
2597ec681f3Smrg               *value++ =
2607ec681f3Smrg                  (&ctx->Light.LightSource[light].Ambient[0])[offset] *
2617ec681f3Smrg                  ctx->Light.Material.Attrib[attrib][chan];
2627ec681f3Smrg            }
2637ec681f3Smrg            /* [3] = material alpha */
2647ec681f3Smrg            *value++ = ctx->Light.Material.Attrib[attrib][3];
2657ec681f3Smrg         }
2667ec681f3Smrg      }
2677ec681f3Smrg      return;
2687ec681f3Smrg   }
2693464ebd5Sriastradh   case STATE_TEXGEN:
2703464ebd5Sriastradh      {
2713464ebd5Sriastradh         /* state[1] is the texture unit */
2723464ebd5Sriastradh         const GLuint unit = (GLuint) state[1];
2733464ebd5Sriastradh         /* state[2] is the texgen attribute */
2747ec681f3Smrg         /* Assertions for the expected memory layout. */
2757ec681f3Smrg#define MEMBER_SIZEOF(type, member) sizeof(((type *)0)->member)
2767ec681f3Smrg         STATIC_ASSERT(MEMBER_SIZEOF(struct gl_fixedfunc_texture_unit,
2777ec681f3Smrg                                     EyePlane[0]) == 4 * sizeof(float));
2787ec681f3Smrg         STATIC_ASSERT(MEMBER_SIZEOF(struct gl_fixedfunc_texture_unit,
2797ec681f3Smrg                                     ObjectPlane[0]) == 4 * sizeof(float));
2807ec681f3Smrg#undef MEMBER_SIZEOF
2817ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S == GEN_T - GEN_S);
2827ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S == GEN_R - GEN_S);
2837ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S == GEN_Q - GEN_S);
2847ec681f3Smrg         STATIC_ASSERT(offsetof(struct gl_fixedfunc_texture_unit, ObjectPlane) -
2857ec681f3Smrg                       offsetof(struct gl_fixedfunc_texture_unit, EyePlane) ==
2867ec681f3Smrg                       (STATE_TEXGEN_OBJECT_S - STATE_TEXGEN_EYE_S) * 4 * sizeof(float));
2877ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_OBJECT_T - STATE_TEXGEN_OBJECT_S == GEN_T - GEN_S);
2887ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_OBJECT_R - STATE_TEXGEN_OBJECT_S == GEN_R - GEN_S);
2897ec681f3Smrg         STATIC_ASSERT(STATE_TEXGEN_OBJECT_Q - STATE_TEXGEN_OBJECT_S == GEN_Q - GEN_S);
2907ec681f3Smrg
2917ec681f3Smrg         const float *attr = (float*)ctx->Texture.FixedFuncUnit[unit].EyePlane +
2927ec681f3Smrg                             (state[2] - STATE_TEXGEN_EYE_S) * 4;
2937ec681f3Smrg         COPY_4V(value, attr);
2947ec681f3Smrg         return;
2953464ebd5Sriastradh      }
2963464ebd5Sriastradh   case STATE_TEXENV_COLOR:
2973464ebd5Sriastradh      {
2983464ebd5Sriastradh         /* state[1] is the texture unit */
2993464ebd5Sriastradh         const GLuint unit = (GLuint) state[1];
30001e04c3fSmrg         if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer))
30101e04c3fSmrg            COPY_4V(value, ctx->Texture.FixedFuncUnit[unit].EnvColor);
3023464ebd5Sriastradh         else
30301e04c3fSmrg            COPY_4V(value, ctx->Texture.FixedFuncUnit[unit].EnvColorUnclamped);
3043464ebd5Sriastradh      }
3053464ebd5Sriastradh      return;
3063464ebd5Sriastradh   case STATE_FOG_COLOR:
30701e04c3fSmrg      if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer))
3083464ebd5Sriastradh         COPY_4V(value, ctx->Fog.Color);
3093464ebd5Sriastradh      else
3103464ebd5Sriastradh         COPY_4V(value, ctx->Fog.ColorUnclamped);
3113464ebd5Sriastradh      return;
3123464ebd5Sriastradh   case STATE_FOG_PARAMS:
3133464ebd5Sriastradh      value[0] = ctx->Fog.Density;
3143464ebd5Sriastradh      value[1] = ctx->Fog.Start;
3153464ebd5Sriastradh      value[2] = ctx->Fog.End;
316af69d88dSmrg      value[3] = 1.0f / (ctx->Fog.End - ctx->Fog.Start);
3173464ebd5Sriastradh      return;
3183464ebd5Sriastradh   case STATE_CLIPPLANE:
3193464ebd5Sriastradh      {
3203464ebd5Sriastradh         const GLuint plane = (GLuint) state[1];
3213464ebd5Sriastradh         COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
3223464ebd5Sriastradh      }
3233464ebd5Sriastradh      return;
3243464ebd5Sriastradh   case STATE_POINT_SIZE:
3253464ebd5Sriastradh      value[0] = ctx->Point.Size;
3263464ebd5Sriastradh      value[1] = ctx->Point.MinSize;
3273464ebd5Sriastradh      value[2] = ctx->Point.MaxSize;
3283464ebd5Sriastradh      value[3] = ctx->Point.Threshold;
3293464ebd5Sriastradh      return;
3303464ebd5Sriastradh   case STATE_POINT_ATTENUATION:
3313464ebd5Sriastradh      value[0] = ctx->Point.Params[0];
3323464ebd5Sriastradh      value[1] = ctx->Point.Params[1];
3333464ebd5Sriastradh      value[2] = ctx->Point.Params[2];
3343464ebd5Sriastradh      value[3] = 1.0F;
3353464ebd5Sriastradh      return;
3367ec681f3Smrg   /* state[0] = modelview, projection, texture, etc. */
3377ec681f3Smrg   /* state[1] = which texture matrix or program matrix */
3387ec681f3Smrg   /* state[2] = first row to fetch */
3397ec681f3Smrg   /* state[3] = last row to fetch */
3407ec681f3Smrg   case STATE_MODELVIEW_MATRIX: {
3417ec681f3Smrg      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
3427ec681f3Smrg      copy_matrix(value, matrix->m, state[2], state[3]);
3437ec681f3Smrg      return;
3447ec681f3Smrg   }
3457ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVERSE: {
3467ec681f3Smrg      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
3477ec681f3Smrg      copy_matrix(value, matrix->inv, state[2], state[3]);
3487ec681f3Smrg      return;
3497ec681f3Smrg   }
3507ec681f3Smrg   case STATE_MODELVIEW_MATRIX_TRANSPOSE: {
3517ec681f3Smrg      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
3527ec681f3Smrg      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
3537ec681f3Smrg      return;
3547ec681f3Smrg   }
3557ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVTRANS: {
3567ec681f3Smrg      const GLmatrix *matrix = ctx->ModelviewMatrixStack.Top;
3577ec681f3Smrg      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
3587ec681f3Smrg      return;
3597ec681f3Smrg   }
3607ec681f3Smrg   case STATE_PROJECTION_MATRIX: {
3617ec681f3Smrg      const GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
3627ec681f3Smrg      copy_matrix(value, matrix->m, state[2], state[3]);
3637ec681f3Smrg      return;
3647ec681f3Smrg   }
3657ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVERSE: {
3667ec681f3Smrg      GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
3677ec681f3Smrg      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
3687ec681f3Smrg      copy_matrix(value, matrix->inv, state[2], state[3]);
3697ec681f3Smrg      return;
3707ec681f3Smrg   }
3717ec681f3Smrg   case STATE_PROJECTION_MATRIX_TRANSPOSE: {
3727ec681f3Smrg      const GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
3737ec681f3Smrg      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
3747ec681f3Smrg      return;
3757ec681f3Smrg   }
3767ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVTRANS: {
3777ec681f3Smrg      GLmatrix *matrix = ctx->ProjectionMatrixStack.Top;
3787ec681f3Smrg      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
3797ec681f3Smrg      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
3807ec681f3Smrg      return;
3817ec681f3Smrg   }
3827ec681f3Smrg   case STATE_MVP_MATRIX: {
3837ec681f3Smrg      const GLmatrix *matrix = &ctx->_ModelProjectMatrix;
3847ec681f3Smrg      copy_matrix(value, matrix->m, state[2], state[3]);
3857ec681f3Smrg      return;
3867ec681f3Smrg   }
3877ec681f3Smrg   case STATE_MVP_MATRIX_INVERSE: {
3887ec681f3Smrg      GLmatrix *matrix = &ctx->_ModelProjectMatrix;
3897ec681f3Smrg      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
3907ec681f3Smrg      copy_matrix(value, matrix->inv, state[2], state[3]);
3917ec681f3Smrg      return;
3927ec681f3Smrg   }
3937ec681f3Smrg   case STATE_MVP_MATRIX_TRANSPOSE: {
3947ec681f3Smrg      const GLmatrix *matrix = &ctx->_ModelProjectMatrix;
3957ec681f3Smrg      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
3963464ebd5Sriastradh      return;
3977ec681f3Smrg   }
3987ec681f3Smrg   case STATE_MVP_MATRIX_INVTRANS: {
3997ec681f3Smrg      GLmatrix *matrix = &ctx->_ModelProjectMatrix;
4007ec681f3Smrg      _math_matrix_analyse(matrix); /* make sure the inverse is up to date */
4017ec681f3Smrg      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
4027ec681f3Smrg      return;
4037ec681f3Smrg   }
4047ec681f3Smrg   case STATE_TEXTURE_MATRIX: {
4057ec681f3Smrg      const GLuint index = (GLuint) state[1];
4067ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
4077ec681f3Smrg      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
4087ec681f3Smrg      copy_matrix(value, matrix->m, state[2], state[3]);
4097ec681f3Smrg      return;
4107ec681f3Smrg   }
4117ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVERSE: {
4127ec681f3Smrg      const GLuint index = (GLuint) state[1];
4137ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
4147ec681f3Smrg      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
4157ec681f3Smrg      copy_matrix(value, matrix->inv, state[2], state[3]);
4167ec681f3Smrg      return;
4177ec681f3Smrg   }
4187ec681f3Smrg   case STATE_TEXTURE_MATRIX_TRANSPOSE: {
4197ec681f3Smrg      const GLuint index = (GLuint) state[1];
4207ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
4217ec681f3Smrg      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
4227ec681f3Smrg      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
4237ec681f3Smrg      return;
4247ec681f3Smrg   }
4257ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVTRANS: {
4267ec681f3Smrg      const GLuint index = (GLuint) state[1];
4277ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->TextureMatrixStack));
4287ec681f3Smrg      const GLmatrix *matrix = ctx->TextureMatrixStack[index].Top;
4297ec681f3Smrg      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
4307ec681f3Smrg      return;
4317ec681f3Smrg   }
4327ec681f3Smrg   case STATE_PROGRAM_MATRIX: {
4337ec681f3Smrg      const GLuint index = (GLuint) state[1];
4347ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
4357ec681f3Smrg      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
4367ec681f3Smrg      copy_matrix(value, matrix->m, state[2], state[3]);
4377ec681f3Smrg      return;
4387ec681f3Smrg   }
4397ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVERSE: {
4407ec681f3Smrg      const GLuint index = (GLuint) state[1];
4417ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
4427ec681f3Smrg      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
4437ec681f3Smrg      _math_matrix_analyse((GLmatrix*)matrix); /* Be sure inverse is up to date: */
4447ec681f3Smrg      copy_matrix(value, matrix->inv, state[2], state[3]);
4457ec681f3Smrg      return;
4467ec681f3Smrg   }
4477ec681f3Smrg   case STATE_PROGRAM_MATRIX_TRANSPOSE: {
4487ec681f3Smrg      const GLuint index = (GLuint) state[1];
4497ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
4507ec681f3Smrg      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
4517ec681f3Smrg      copy_matrix_transposed(value, matrix->m, state[2], state[3]);
4527ec681f3Smrg      return;
4537ec681f3Smrg   }
4547ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVTRANS: {
4557ec681f3Smrg      const GLuint index = (GLuint) state[1];
4567ec681f3Smrg      assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack));
4577ec681f3Smrg      const GLmatrix *matrix = ctx->ProgramMatrixStack[index].Top;
4587ec681f3Smrg      _math_matrix_analyse((GLmatrix*)matrix); /* Be sure inverse is up to date: */
4597ec681f3Smrg      copy_matrix_transposed(value, matrix->inv, state[2], state[3]);
4607ec681f3Smrg      return;
4617ec681f3Smrg   }
462af69d88dSmrg   case STATE_NUM_SAMPLES:
46301e04c3fSmrg      val[0].i = MAX2(1, _mesa_geometric_samples(ctx->DrawBuffer));
464af69d88dSmrg      return;
4653464ebd5Sriastradh   case STATE_DEPTH_RANGE:
466af69d88dSmrg      value[0] = ctx->ViewportArray[0].Near;                /* near       */
467af69d88dSmrg      value[1] = ctx->ViewportArray[0].Far;                 /* far        */
468af69d88dSmrg      value[2] = ctx->ViewportArray[0].Far - ctx->ViewportArray[0].Near; /* far - near */
4693464ebd5Sriastradh      value[3] = 1.0;
4703464ebd5Sriastradh      return;
4717ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV: {
4727ec681f3Smrg      const int idx = (int) state[1];
4737ec681f3Smrg      COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
4747ec681f3Smrg      return;
4757ec681f3Smrg   }
4767ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY: {
4777ec681f3Smrg      const unsigned idx = state[1];
4787ec681f3Smrg      const unsigned bytes = state[2] * 16;
4797ec681f3Smrg      memcpy(value, ctx->FragmentProgram.Parameters[idx], bytes);
4807ec681f3Smrg      return;
4817ec681f3Smrg   }
4827ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL: {
4837ec681f3Smrg      float (*params)[4] = ctx->FragmentProgram.Current->arb.LocalParams;
4847ec681f3Smrg      if (unlikely(!params)) {
4857ec681f3Smrg         /* Local parameters haven't been allocated yet.
4867ec681f3Smrg          * ARB_fragment_program says that local parameters are
4877ec681f3Smrg          * "initially set to (0,0,0,0)." Return that.
4887ec681f3Smrg          */
4897ec681f3Smrg         memset(value, 0, sizeof(float) * 4);
4907ec681f3Smrg         return;
4917ec681f3Smrg      }
492af69d88dSmrg
4937ec681f3Smrg      const int idx = (int) state[1];
4947ec681f3Smrg      COPY_4V(value, params[idx]);
4957ec681f3Smrg      return;
4967ec681f3Smrg   }
4977ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY: {
4987ec681f3Smrg      const unsigned idx = state[1];
4997ec681f3Smrg      const unsigned bytes = state[2] * 16;
5007ec681f3Smrg      float (*params)[4] = ctx->FragmentProgram.Current->arb.LocalParams;
5017ec681f3Smrg      if (!params) {
5027ec681f3Smrg         /* Local parameters haven't been allocated yet.
5037ec681f3Smrg          * ARB_fragment_program says that local parameters are
5047ec681f3Smrg          * "initially set to (0,0,0,0)." Return that.
5057ec681f3Smrg          */
5067ec681f3Smrg         memset(value, 0, bytes);
5077ec681f3Smrg         return;
5083464ebd5Sriastradh      }
5097ec681f3Smrg      memcpy(value, params[idx], bytes);
5107ec681f3Smrg      return;
5117ec681f3Smrg   }
5127ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV: {
5137ec681f3Smrg      const int idx = (int) state[1];
5147ec681f3Smrg      COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
5157ec681f3Smrg      return;
5167ec681f3Smrg   }
5177ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV_ARRAY: {
5187ec681f3Smrg      const unsigned idx = state[1];
5197ec681f3Smrg      const unsigned bytes = state[2] * 16;
5207ec681f3Smrg      memcpy(value, ctx->VertexProgram.Parameters[idx], bytes);
5213464ebd5Sriastradh      return;
5227ec681f3Smrg   }
5237ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL: {
5247ec681f3Smrg      float (*params)[4] = ctx->VertexProgram.Current->arb.LocalParams;
5257ec681f3Smrg      if (unlikely(!params)) {
5267ec681f3Smrg         /* Local parameters haven't been allocated yet.
5277ec681f3Smrg          * ARB_vertex_program says that local parameters are
5287ec681f3Smrg          * "initially set to (0,0,0,0)." Return that.
5297ec681f3Smrg          */
5307ec681f3Smrg         memset(value, 0, sizeof(float) * 4);
5317ec681f3Smrg         return;
5327ec681f3Smrg      }
5333464ebd5Sriastradh
5347ec681f3Smrg      const int idx = (int) state[1];
5357ec681f3Smrg      COPY_4V(value, params[idx]);
5367ec681f3Smrg      return;
5377ec681f3Smrg   }
5387ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY: {
5397ec681f3Smrg      const unsigned idx = state[1];
5407ec681f3Smrg      const unsigned bytes = state[2] * 16;
5417ec681f3Smrg      float (*params)[4] = ctx->VertexProgram.Current->arb.LocalParams;
5427ec681f3Smrg      if (!params) {
5437ec681f3Smrg         /* Local parameters haven't been allocated yet.
5447ec681f3Smrg          * ARB_vertex_program says that local parameters are
5457ec681f3Smrg          * "initially set to (0,0,0,0)." Return that.
5467ec681f3Smrg          */
5477ec681f3Smrg         memset(value, 0, bytes);
5487ec681f3Smrg         return;
5497ec681f3Smrg      }
5507ec681f3Smrg      memcpy(value, params[idx], bytes);
5517ec681f3Smrg      return;
5527ec681f3Smrg   }
5537ec681f3Smrg
5547ec681f3Smrg   case STATE_NORMAL_SCALE_EYESPACE:
5557ec681f3Smrg      ASSIGN_4V(value, ctx->_ModelViewInvScaleEyespace, 0, 0, 1);
5567ec681f3Smrg      return;
5577ec681f3Smrg
5587ec681f3Smrg   case STATE_CURRENT_ATTRIB:
5593464ebd5Sriastradh      {
5607ec681f3Smrg         const GLuint idx = (GLuint) state[1];
5617ec681f3Smrg         COPY_4V(value, ctx->Current.Attrib[idx]);
5627ec681f3Smrg      }
5637ec681f3Smrg      return;
564af69d88dSmrg
5657ec681f3Smrg   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
5667ec681f3Smrg      {
5677ec681f3Smrg         const GLuint idx = (GLuint) state[1];
5687ec681f3Smrg         if(ctx->Light._ClampVertexColor &&
5697ec681f3Smrg            (idx == VERT_ATTRIB_COLOR0 ||
5707ec681f3Smrg             idx == VERT_ATTRIB_COLOR1)) {
5717ec681f3Smrg            value[0] = SATURATE(ctx->Current.Attrib[idx][0]);
5727ec681f3Smrg            value[1] = SATURATE(ctx->Current.Attrib[idx][1]);
5737ec681f3Smrg            value[2] = SATURATE(ctx->Current.Attrib[idx][2]);
5747ec681f3Smrg            value[3] = SATURATE(ctx->Current.Attrib[idx][3]);
5753464ebd5Sriastradh         }
5767ec681f3Smrg         else
5777ec681f3Smrg            COPY_4V(value, ctx->Current.Attrib[idx]);
5783464ebd5Sriastradh      }
5793464ebd5Sriastradh      return;
5803464ebd5Sriastradh
5813464ebd5Sriastradh   case STATE_NORMAL_SCALE:
5827ec681f3Smrg      ASSIGN_4V(value,
5837ec681f3Smrg                ctx->_ModelViewInvScale,
5847ec681f3Smrg                ctx->_ModelViewInvScale,
5857ec681f3Smrg                ctx->_ModelViewInvScale,
5867ec681f3Smrg                1);
5873464ebd5Sriastradh      return;
5883464ebd5Sriastradh
5897ec681f3Smrg   case STATE_FOG_PARAMS_OPTIMIZED: {
5907ec681f3Smrg      /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog)
5917ec681f3Smrg       * might be more expensive than EX2 on some hw, plus it needs
5927ec681f3Smrg       * another constant (e) anyway. Linear fog can now be done with a
5937ec681f3Smrg       * single MAD.
5947ec681f3Smrg       * linear: fogcoord * -1/(end-start) + end/(end-start)
5957ec681f3Smrg       * exp: 2^-(density/ln(2) * fogcoord)
5967ec681f3Smrg       * exp2: 2^-((density/(sqrt(ln(2))) * fogcoord)^2)
5977ec681f3Smrg       */
5987ec681f3Smrg      float val =  (ctx->Fog.End == ctx->Fog.Start)
5997ec681f3Smrg         ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start));
6007ec681f3Smrg      value[0] = val;
6017ec681f3Smrg      value[1] = ctx->Fog.End * -val;
6027ec681f3Smrg      value[2] = (GLfloat)(ctx->Fog.Density * M_LOG2E); /* M_LOG2E == 1/ln(2) */
6037ec681f3Smrg      value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2);
6047ec681f3Smrg      return;
6057ec681f3Smrg   }
6063464ebd5Sriastradh
6077ec681f3Smrg   case STATE_POINT_SIZE_CLAMPED:
6087ec681f3Smrg      {
6097ec681f3Smrg        /* this includes implementation dependent limits, to avoid
6107ec681f3Smrg         * another potentially necessary clamp.
6117ec681f3Smrg         * Note: for sprites, point smooth (point AA) is ignored
6127ec681f3Smrg         * and we'll clamp to MinPointSizeAA and MaxPointSize, because we
6137ec681f3Smrg         * expect drivers will want to say their minimum for AA size is 0.0
6147ec681f3Smrg         * but for non-AA it's 1.0 (because normal points with size below 1.0
6157ec681f3Smrg         * need to get rounded up to 1.0, hence never disappear). GL does
6167ec681f3Smrg         * not specify max clamp size for sprites, other than it needs to be
6177ec681f3Smrg         * at least as large as max AA size, hence use non-AA size there.
6187ec681f3Smrg         */
6197ec681f3Smrg         GLfloat minImplSize;
6207ec681f3Smrg         GLfloat maxImplSize;
6217ec681f3Smrg         if (ctx->Point.PointSprite) {
6227ec681f3Smrg            minImplSize = ctx->Const.MinPointSizeAA;
6237ec681f3Smrg            maxImplSize = ctx->Const.MaxPointSize;
6243464ebd5Sriastradh         }
6257ec681f3Smrg         else if (ctx->Point.SmoothFlag || _mesa_is_multisample_enabled(ctx)) {
6267ec681f3Smrg            minImplSize = ctx->Const.MinPointSizeAA;
6277ec681f3Smrg            maxImplSize = ctx->Const.MaxPointSizeAA;
6287ec681f3Smrg         }
6297ec681f3Smrg         else {
6307ec681f3Smrg            minImplSize = ctx->Const.MinPointSize;
6317ec681f3Smrg            maxImplSize = ctx->Const.MaxPointSize;
6327ec681f3Smrg         }
6337ec681f3Smrg         value[0] = ctx->Point.Size;
6347ec681f3Smrg         value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize;
6357ec681f3Smrg         value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize;
6367ec681f3Smrg         value[3] = ctx->Point.Threshold;
6377ec681f3Smrg      }
6387ec681f3Smrg      return;
6397ec681f3Smrg   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
6407ec681f3Smrg      {
6417ec681f3Smrg         /* here, state[1] is the light number */
6427ec681f3Smrg         /* pre-normalize spot dir */
6437ec681f3Smrg         const GLuint ln = (GLuint) state[1];
6447ec681f3Smrg         COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection);
6457ec681f3Smrg         value[3] = ctx->Light.LightSource[ln]._CosCutoff;
6467ec681f3Smrg      }
6477ec681f3Smrg      return;
6483464ebd5Sriastradh
6497ec681f3Smrg   case STATE_LIGHT_POSITION:
6507ec681f3Smrg      {
6517ec681f3Smrg         const GLuint ln = (GLuint) state[1];
6527ec681f3Smrg         COPY_4V(value, ctx->Light.Light[ln]._Position);
6537ec681f3Smrg      }
6547ec681f3Smrg      return;
6553464ebd5Sriastradh
6567ec681f3Smrg   case STATE_LIGHT_POSITION_ARRAY: {
6577ec681f3Smrg      const unsigned first = state[1];
6587ec681f3Smrg      const unsigned num_lights = state[2];
6597ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
6607ec681f3Smrg         COPY_4V(value, ctx->Light.Light[first + i]._Position);
6617ec681f3Smrg         value += 4;
6627ec681f3Smrg      }
6637ec681f3Smrg      return;
6647ec681f3Smrg   }
6653464ebd5Sriastradh
6667ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED:
6677ec681f3Smrg      {
6687ec681f3Smrg         const GLuint ln = (GLuint) state[1];
6697ec681f3Smrg         float p[4];
6707ec681f3Smrg         COPY_4V(p, ctx->Light.Light[ln]._Position);
6717ec681f3Smrg         NORMALIZE_3FV(p);
6727ec681f3Smrg         COPY_4V(value, p);
6737ec681f3Smrg      }
6747ec681f3Smrg      return;
6753464ebd5Sriastradh
6767ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY: {
6777ec681f3Smrg      const unsigned first = state[1];
6787ec681f3Smrg      const unsigned num_lights = state[2];
6797ec681f3Smrg      for (unsigned i = 0; i < num_lights; i++) {
6807ec681f3Smrg         float p[4];
6817ec681f3Smrg         COPY_4V(p, ctx->Light.Light[first + i]._Position);
6827ec681f3Smrg         NORMALIZE_3FV(p);
6837ec681f3Smrg         COPY_4V(value, p);
6847ec681f3Smrg         value += 4;
6857ec681f3Smrg      }
6867ec681f3Smrg      return;
6877ec681f3Smrg   }
6883464ebd5Sriastradh
6897ec681f3Smrg   case STATE_LIGHT_HALF_VECTOR:
6907ec681f3Smrg      {
6917ec681f3Smrg         const GLuint ln = (GLuint) state[1];
6927ec681f3Smrg         GLfloat p[3];
6937ec681f3Smrg         /* Compute infinite half angle vector:
6947ec681f3Smrg          *   halfVector = normalize(normalize(lightPos) + (0, 0, 1))
6957ec681f3Smrg          * light.EyePosition.w should be 0 for infinite lights.
6967ec681f3Smrg          */
6977ec681f3Smrg         COPY_3V(p, ctx->Light.Light[ln]._Position);
6987ec681f3Smrg         NORMALIZE_3FV(p);
6997ec681f3Smrg         ADD_3V(p, p, ctx->_EyeZDir);
7007ec681f3Smrg         NORMALIZE_3FV(p);
7017ec681f3Smrg         COPY_3V(value, p);
7027ec681f3Smrg         value[3] = 1.0;
7037ec681f3Smrg      }
7047ec681f3Smrg      return;
7053464ebd5Sriastradh
7067ec681f3Smrg   case STATE_PT_SCALE:
7077ec681f3Smrg      value[0] = ctx->Pixel.RedScale;
7087ec681f3Smrg      value[1] = ctx->Pixel.GreenScale;
7097ec681f3Smrg      value[2] = ctx->Pixel.BlueScale;
7107ec681f3Smrg      value[3] = ctx->Pixel.AlphaScale;
7117ec681f3Smrg      return;
7123464ebd5Sriastradh
7137ec681f3Smrg   case STATE_PT_BIAS:
7147ec681f3Smrg      value[0] = ctx->Pixel.RedBias;
7157ec681f3Smrg      value[1] = ctx->Pixel.GreenBias;
7167ec681f3Smrg      value[2] = ctx->Pixel.BlueBias;
7177ec681f3Smrg      value[3] = ctx->Pixel.AlphaBias;
7187ec681f3Smrg      return;
7193464ebd5Sriastradh
7207ec681f3Smrg   case STATE_FB_SIZE:
7217ec681f3Smrg      value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1);
7227ec681f3Smrg      value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
7237ec681f3Smrg      value[2] = 0.0F;
7247ec681f3Smrg      value[3] = 0.0F;
7257ec681f3Smrg      return;
7267ec681f3Smrg
7277ec681f3Smrg   case STATE_FB_WPOS_Y_TRANSFORM:
7287ec681f3Smrg      /* A driver may negate this conditional by using ZW swizzle
7297ec681f3Smrg       * instead of XY (based on e.g. some other state). */
7307ec681f3Smrg      if (!ctx->DrawBuffer->FlipY) {
7317ec681f3Smrg         /* Identity (XY) followed by flipping Y upside down (ZW). */
7327ec681f3Smrg         value[0] = 1.0F;
7337ec681f3Smrg         value[1] = 0.0F;
7347ec681f3Smrg         value[2] = -1.0F;
7357ec681f3Smrg         value[3] = _mesa_geometric_height(ctx->DrawBuffer);
7367ec681f3Smrg      } else {
7377ec681f3Smrg         /* Flipping Y upside down (XY) followed by identity (ZW). */
7387ec681f3Smrg         value[0] = -1.0F;
7397ec681f3Smrg         value[1] = _mesa_geometric_height(ctx->DrawBuffer);
7407ec681f3Smrg         value[2] = 1.0F;
7417ec681f3Smrg         value[3] = 0.0F;
7427ec681f3Smrg      }
7437ec681f3Smrg      return;
7447ec681f3Smrg
7457ec681f3Smrg   case STATE_FB_PNTC_Y_TRANSFORM:
7467ec681f3Smrg      {
7477ec681f3Smrg         bool flip_y = (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) ^
7487ec681f3Smrg            (ctx->DrawBuffer->FlipY);
7493464ebd5Sriastradh
7507ec681f3Smrg         value[0] = flip_y ? -1.0F : 1.0F;
7517ec681f3Smrg         value[1] = flip_y ? 1.0F : 0.0F;
7523464ebd5Sriastradh         value[2] = 0.0F;
7533464ebd5Sriastradh         value[3] = 0.0F;
7547ec681f3Smrg      }
7557ec681f3Smrg      return;
7563464ebd5Sriastradh
7577ec681f3Smrg   case STATE_TCS_PATCH_VERTICES_IN:
7587ec681f3Smrg      val[0].i = ctx->TessCtrlProgram.patch_vertices;
7597ec681f3Smrg      return;
7603464ebd5Sriastradh
7617ec681f3Smrg   case STATE_TES_PATCH_VERTICES_IN:
7627ec681f3Smrg      if (ctx->TessCtrlProgram._Current)
7637ec681f3Smrg         val[0].i = ctx->TessCtrlProgram._Current->info.tess.tcs_vertices_out;
7647ec681f3Smrg      else
76501e04c3fSmrg         val[0].i = ctx->TessCtrlProgram.patch_vertices;
7667ec681f3Smrg      return;
76701e04c3fSmrg
7687ec681f3Smrg   case STATE_ADVANCED_BLENDING_MODE:
7697ec681f3Smrg      val[0].i = _mesa_get_advanced_blend_sh_constant(
7707ec681f3Smrg                   ctx->Color.BlendEnabled, ctx->Color._AdvancedBlendMode);
7717ec681f3Smrg      return;
77201e04c3fSmrg
7737ec681f3Smrg   case STATE_ALPHA_REF:
7747ec681f3Smrg      value[0] = ctx->Color.AlphaRefUnclamped;
7753464ebd5Sriastradh      return;
7763464ebd5Sriastradh
7777ec681f3Smrg   case STATE_CLIP_INTERNAL:
7787ec681f3Smrg      {
7797ec681f3Smrg         const GLuint plane = (GLuint) state[1];
7807ec681f3Smrg         COPY_4V(value, ctx->Transform._ClipUserPlane[plane]);
7817ec681f3Smrg      }
7823464ebd5Sriastradh      return;
7833464ebd5Sriastradh   }
7843464ebd5Sriastradh}
7853464ebd5Sriastradh
7867ec681f3Smrgunsigned
7877ec681f3Smrg_mesa_program_state_value_size(const gl_state_index16 state[STATE_LENGTH])
7887ec681f3Smrg{
7897ec681f3Smrg   if (state[0] == STATE_LIGHT && state[2] == STATE_SPOT_CUTOFF)
7907ec681f3Smrg      return 1;
7917ec681f3Smrg
7927ec681f3Smrg   /* Everything else is packed into vec4s */
7937ec681f3Smrg   return 4;
7947ec681f3Smrg}
7953464ebd5Sriastradh
7963464ebd5Sriastradh/**
7973464ebd5Sriastradh * Return a bitmask of the Mesa state flags (_NEW_* values) which would
7983464ebd5Sriastradh * indicate that the given context state may have changed.
7993464ebd5Sriastradh * The bitmask is used during validation to determine if we need to update
8003464ebd5Sriastradh * vertex/fragment program parameters (like "state.material.color") when
8013464ebd5Sriastradh * some GL state has changed.
8023464ebd5Sriastradh */
8033464ebd5SriastradhGLbitfield
80401e04c3fSmrg_mesa_program_state_flags(const gl_state_index16 state[STATE_LENGTH])
8053464ebd5Sriastradh{
8063464ebd5Sriastradh   switch (state[0]) {
8073464ebd5Sriastradh   case STATE_MATERIAL:
8087ec681f3Smrg      return _NEW_MATERIAL;
8097ec681f3Smrg
8103464ebd5Sriastradh   case STATE_LIGHTPROD:
8117ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_FRONT:
8127ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_BACK:
8137ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
8143464ebd5Sriastradh   case STATE_LIGHTMODEL_SCENECOLOR:
8157ec681f3Smrg      return _NEW_LIGHT_CONSTANTS | _NEW_MATERIAL;
8163464ebd5Sriastradh
8173464ebd5Sriastradh   case STATE_LIGHT:
8187ec681f3Smrg   case STATE_LIGHT_ARRAY:
8197ec681f3Smrg   case STATE_LIGHT_ATTENUATION_ARRAY:
8203464ebd5Sriastradh   case STATE_LIGHTMODEL_AMBIENT:
8217ec681f3Smrg   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
8227ec681f3Smrg   case STATE_LIGHT_POSITION:
8237ec681f3Smrg   case STATE_LIGHT_POSITION_ARRAY:
8247ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED:
8257ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
8267ec681f3Smrg   case STATE_LIGHT_HALF_VECTOR:
8277ec681f3Smrg      return _NEW_LIGHT_CONSTANTS;
8283464ebd5Sriastradh
8293464ebd5Sriastradh   case STATE_TEXGEN:
83001e04c3fSmrg      return _NEW_TEXTURE_STATE;
8313464ebd5Sriastradh   case STATE_TEXENV_COLOR:
83201e04c3fSmrg      return _NEW_TEXTURE_STATE | _NEW_BUFFERS | _NEW_FRAG_CLAMP;
8333464ebd5Sriastradh
8343464ebd5Sriastradh   case STATE_FOG_COLOR:
8353464ebd5Sriastradh      return _NEW_FOG | _NEW_BUFFERS | _NEW_FRAG_CLAMP;
8363464ebd5Sriastradh   case STATE_FOG_PARAMS:
8377ec681f3Smrg   case STATE_FOG_PARAMS_OPTIMIZED:
8383464ebd5Sriastradh      return _NEW_FOG;
8393464ebd5Sriastradh
8403464ebd5Sriastradh   case STATE_CLIPPLANE:
8413464ebd5Sriastradh      return _NEW_TRANSFORM;
8423464ebd5Sriastradh
8433464ebd5Sriastradh   case STATE_POINT_SIZE:
8443464ebd5Sriastradh   case STATE_POINT_ATTENUATION:
8453464ebd5Sriastradh      return _NEW_POINT;
8463464ebd5Sriastradh
8473464ebd5Sriastradh   case STATE_MODELVIEW_MATRIX:
8487ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVERSE:
8497ec681f3Smrg   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
8507ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVTRANS:
8517ec681f3Smrg   case STATE_NORMAL_SCALE_EYESPACE:
8527ec681f3Smrg   case STATE_NORMAL_SCALE:
8533464ebd5Sriastradh      return _NEW_MODELVIEW;
8547ec681f3Smrg
8553464ebd5Sriastradh   case STATE_PROJECTION_MATRIX:
8567ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVERSE:
8577ec681f3Smrg   case STATE_PROJECTION_MATRIX_TRANSPOSE:
8587ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVTRANS:
8593464ebd5Sriastradh      return _NEW_PROJECTION;
8603464ebd5Sriastradh   case STATE_MVP_MATRIX:
8617ec681f3Smrg   case STATE_MVP_MATRIX_INVERSE:
8627ec681f3Smrg   case STATE_MVP_MATRIX_TRANSPOSE:
8637ec681f3Smrg   case STATE_MVP_MATRIX_INVTRANS:
8643464ebd5Sriastradh      return _NEW_MODELVIEW | _NEW_PROJECTION;
8653464ebd5Sriastradh   case STATE_TEXTURE_MATRIX:
8667ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVERSE:
8677ec681f3Smrg   case STATE_TEXTURE_MATRIX_TRANSPOSE:
8687ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVTRANS:
8693464ebd5Sriastradh      return _NEW_TEXTURE_MATRIX;
8703464ebd5Sriastradh   case STATE_PROGRAM_MATRIX:
8717ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVERSE:
8727ec681f3Smrg   case STATE_PROGRAM_MATRIX_TRANSPOSE:
8737ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVTRANS:
8743464ebd5Sriastradh      return _NEW_TRACK_MATRIX;
8753464ebd5Sriastradh
876af69d88dSmrg   case STATE_NUM_SAMPLES:
8777ec681f3Smrg   case STATE_FB_SIZE:
8787ec681f3Smrg   case STATE_FB_WPOS_Y_TRANSFORM:
879af69d88dSmrg      return _NEW_BUFFERS;
880af69d88dSmrg
8817ec681f3Smrg   case STATE_FB_PNTC_Y_TRANSFORM:
8827ec681f3Smrg      return _NEW_BUFFERS | _NEW_POINT;
8837ec681f3Smrg
8843464ebd5Sriastradh   case STATE_DEPTH_RANGE:
8853464ebd5Sriastradh      return _NEW_VIEWPORT;
8863464ebd5Sriastradh
8877ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV:
8887ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
8897ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL:
8907ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
8917ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV:
8927ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
8937ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL:
8947ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
8953464ebd5Sriastradh      return _NEW_PROGRAM;
8963464ebd5Sriastradh
8977ec681f3Smrg   case STATE_CURRENT_ATTRIB:
8987ec681f3Smrg      return _NEW_CURRENT_ATTRIB;
8997ec681f3Smrg   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
9007ec681f3Smrg      return _NEW_CURRENT_ATTRIB | _NEW_LIGHT_STATE | _NEW_BUFFERS;
9013464ebd5Sriastradh
9027ec681f3Smrg   case STATE_POINT_SIZE_CLAMPED:
9037ec681f3Smrg      return _NEW_POINT | _NEW_MULTISAMPLE;
9043464ebd5Sriastradh
9057ec681f3Smrg   case STATE_PT_SCALE:
9067ec681f3Smrg   case STATE_PT_BIAS:
9077ec681f3Smrg      return _NEW_PIXEL;
9083464ebd5Sriastradh
9097ec681f3Smrg   case STATE_ADVANCED_BLENDING_MODE:
9107ec681f3Smrg   case STATE_ALPHA_REF:
9117ec681f3Smrg      return _NEW_COLOR;
9123464ebd5Sriastradh
9137ec681f3Smrg   case STATE_CLIP_INTERNAL:
9147ec681f3Smrg      return _NEW_TRANSFORM | _NEW_PROJECTION;
91501e04c3fSmrg
9167ec681f3Smrg   case STATE_TCS_PATCH_VERTICES_IN:
9177ec681f3Smrg   case STATE_TES_PATCH_VERTICES_IN:
9187ec681f3Smrg   case STATE_INTERNAL_DRIVER:
9197ec681f3Smrg      return 0; /* internal driver state */
9207ec681f3Smrg
9217ec681f3Smrg   case STATE_NOT_STATE_VAR:
9227ec681f3Smrg      return 0;
9233464ebd5Sriastradh
9243464ebd5Sriastradh   default:
9253464ebd5Sriastradh      _mesa_problem(NULL, "unexpected state[0] in make_state_flags()");
9263464ebd5Sriastradh      return 0;
9273464ebd5Sriastradh   }
9283464ebd5Sriastradh}
9293464ebd5Sriastradh
9303464ebd5Sriastradh
9313464ebd5Sriastradhstatic void
9323464ebd5Sriastradhappend(char *dst, const char *src)
9333464ebd5Sriastradh{
9343464ebd5Sriastradh   while (*dst)
9353464ebd5Sriastradh      dst++;
9363464ebd5Sriastradh   while (*src)
9373464ebd5Sriastradh     *dst++ = *src++;
9383464ebd5Sriastradh   *dst = 0;
9393464ebd5Sriastradh}
9403464ebd5Sriastradh
9413464ebd5Sriastradh
9423464ebd5Sriastradh/**
9433464ebd5Sriastradh * Convert token 'k' to a string, append it onto 'dst' string.
9443464ebd5Sriastradh */
9453464ebd5Sriastradhstatic void
9463464ebd5Sriastradhappend_token(char *dst, gl_state_index k)
9473464ebd5Sriastradh{
9483464ebd5Sriastradh   switch (k) {
9493464ebd5Sriastradh   case STATE_MATERIAL:
9503464ebd5Sriastradh      append(dst, "material");
9513464ebd5Sriastradh      break;
9523464ebd5Sriastradh   case STATE_LIGHT:
9533464ebd5Sriastradh      append(dst, "light");
9543464ebd5Sriastradh      break;
9557ec681f3Smrg   case STATE_LIGHT_ARRAY:
9567ec681f3Smrg      append(dst, "light.array");
9577ec681f3Smrg      break;
9587ec681f3Smrg   case STATE_LIGHT_ATTENUATION_ARRAY:
9597ec681f3Smrg      append(dst, "light.attenuation");
9607ec681f3Smrg      break;
9613464ebd5Sriastradh   case STATE_LIGHTMODEL_AMBIENT:
9623464ebd5Sriastradh      append(dst, "lightmodel.ambient");
9633464ebd5Sriastradh      break;
9643464ebd5Sriastradh   case STATE_LIGHTMODEL_SCENECOLOR:
9653464ebd5Sriastradh      break;
9663464ebd5Sriastradh   case STATE_LIGHTPROD:
9673464ebd5Sriastradh      append(dst, "lightprod");
9683464ebd5Sriastradh      break;
9697ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_FRONT:
9707ec681f3Smrg      append(dst, "lightprod.array.front");
9717ec681f3Smrg      break;
9727ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_BACK:
9737ec681f3Smrg      append(dst, "lightprod.array.back");
9747ec681f3Smrg      break;
9757ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
9767ec681f3Smrg      append(dst, "lightprod.array.twoside");
9777ec681f3Smrg      break;
9783464ebd5Sriastradh   case STATE_TEXGEN:
9793464ebd5Sriastradh      append(dst, "texgen");
9803464ebd5Sriastradh      break;
9813464ebd5Sriastradh   case STATE_FOG_COLOR:
9823464ebd5Sriastradh      append(dst, "fog.color");
9833464ebd5Sriastradh      break;
9843464ebd5Sriastradh   case STATE_FOG_PARAMS:
9853464ebd5Sriastradh      append(dst, "fog.params");
9863464ebd5Sriastradh      break;
9873464ebd5Sriastradh   case STATE_CLIPPLANE:
9883464ebd5Sriastradh      append(dst, "clip");
9893464ebd5Sriastradh      break;
9903464ebd5Sriastradh   case STATE_POINT_SIZE:
9913464ebd5Sriastradh      append(dst, "point.size");
9923464ebd5Sriastradh      break;
9933464ebd5Sriastradh   case STATE_POINT_ATTENUATION:
9943464ebd5Sriastradh      append(dst, "point.attenuation");
9953464ebd5Sriastradh      break;
9963464ebd5Sriastradh   case STATE_MODELVIEW_MATRIX:
9977ec681f3Smrg      append(dst, "matrix.modelview.");
9987ec681f3Smrg      break;
9997ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVERSE:
10007ec681f3Smrg      append(dst, "matrix.modelview.inverse.");
10017ec681f3Smrg      break;
10027ec681f3Smrg   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
10037ec681f3Smrg      append(dst, "matrix.modelview.transpose.");
10047ec681f3Smrg      break;
10057ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVTRANS:
10067ec681f3Smrg      append(dst, "matrix.modelview.invtrans.");
10073464ebd5Sriastradh      break;
10083464ebd5Sriastradh   case STATE_PROJECTION_MATRIX:
10097ec681f3Smrg      append(dst, "matrix.projection.");
10107ec681f3Smrg      break;
10117ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVERSE:
10127ec681f3Smrg      append(dst, "matrix.projection.inverse.");
10137ec681f3Smrg      break;
10147ec681f3Smrg   case STATE_PROJECTION_MATRIX_TRANSPOSE:
10157ec681f3Smrg      append(dst, "matrix.projection.transpose.");
10167ec681f3Smrg      break;
10177ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVTRANS:
10187ec681f3Smrg      append(dst, "matrix.projection.invtrans.");
10193464ebd5Sriastradh      break;
10203464ebd5Sriastradh   case STATE_MVP_MATRIX:
10217ec681f3Smrg      append(dst, "matrix.mvp.");
10227ec681f3Smrg      break;
10237ec681f3Smrg   case STATE_MVP_MATRIX_INVERSE:
10247ec681f3Smrg      append(dst, "matrix.mvp.inverse.");
10257ec681f3Smrg      break;
10267ec681f3Smrg   case STATE_MVP_MATRIX_TRANSPOSE:
10277ec681f3Smrg      append(dst, "matrix.mvp.transpose.");
10287ec681f3Smrg      break;
10297ec681f3Smrg   case STATE_MVP_MATRIX_INVTRANS:
10307ec681f3Smrg      append(dst, "matrix.mvp.invtrans.");
10313464ebd5Sriastradh      break;
10323464ebd5Sriastradh   case STATE_TEXTURE_MATRIX:
10333464ebd5Sriastradh      append(dst, "matrix.texture");
10343464ebd5Sriastradh      break;
10357ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVERSE:
10367ec681f3Smrg      append(dst, "matrix.texture.inverse");
10377ec681f3Smrg      break;
10387ec681f3Smrg   case STATE_TEXTURE_MATRIX_TRANSPOSE:
10397ec681f3Smrg      append(dst, "matrix.texture.transpose");
10407ec681f3Smrg      break;
10417ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVTRANS:
10427ec681f3Smrg      append(dst, "matrix.texture.invtrans");
10437ec681f3Smrg      break;
10443464ebd5Sriastradh   case STATE_PROGRAM_MATRIX:
10453464ebd5Sriastradh      append(dst, "matrix.program");
10463464ebd5Sriastradh      break;
10477ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVERSE:
10487ec681f3Smrg      append(dst, "matrix.program.inverse");
10493464ebd5Sriastradh      break;
10507ec681f3Smrg   case STATE_PROGRAM_MATRIX_TRANSPOSE:
10517ec681f3Smrg      append(dst, "matrix.program.transpose");
10527ec681f3Smrg      break;
10537ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVTRANS:
10547ec681f3Smrg      append(dst, "matrix.program.invtrans");
10553464ebd5Sriastradh      break;
10563464ebd5Sriastradh      break;
10573464ebd5Sriastradh   case STATE_AMBIENT:
10587ec681f3Smrg      append(dst, "ambient");
10593464ebd5Sriastradh      break;
10603464ebd5Sriastradh   case STATE_DIFFUSE:
10617ec681f3Smrg      append(dst, "diffuse");
10623464ebd5Sriastradh      break;
10633464ebd5Sriastradh   case STATE_SPECULAR:
10647ec681f3Smrg      append(dst, "specular");
10653464ebd5Sriastradh      break;
10663464ebd5Sriastradh   case STATE_EMISSION:
10677ec681f3Smrg      append(dst, "emission");
10683464ebd5Sriastradh      break;
10693464ebd5Sriastradh   case STATE_SHININESS:
10707ec681f3Smrg      append(dst, "shininess");
10713464ebd5Sriastradh      break;
10723464ebd5Sriastradh   case STATE_HALF_VECTOR:
10737ec681f3Smrg      append(dst, "half");
10743464ebd5Sriastradh      break;
10753464ebd5Sriastradh   case STATE_POSITION:
10767ec681f3Smrg      append(dst, "position");
10773464ebd5Sriastradh      break;
10783464ebd5Sriastradh   case STATE_ATTENUATION:
10797ec681f3Smrg      append(dst, "attenuation");
10803464ebd5Sriastradh      break;
10813464ebd5Sriastradh   case STATE_SPOT_DIRECTION:
10827ec681f3Smrg      append(dst, "spot.direction");
10833464ebd5Sriastradh      break;
10843464ebd5Sriastradh   case STATE_SPOT_CUTOFF:
10857ec681f3Smrg      append(dst, "spot.cutoff");
10863464ebd5Sriastradh      break;
10873464ebd5Sriastradh   case STATE_TEXGEN_EYE_S:
10887ec681f3Smrg      append(dst, "eye.s");
10893464ebd5Sriastradh      break;
10903464ebd5Sriastradh   case STATE_TEXGEN_EYE_T:
10917ec681f3Smrg      append(dst, "eye.t");
10923464ebd5Sriastradh      break;
10933464ebd5Sriastradh   case STATE_TEXGEN_EYE_R:
10947ec681f3Smrg      append(dst, "eye.r");
10953464ebd5Sriastradh      break;
10963464ebd5Sriastradh   case STATE_TEXGEN_EYE_Q:
10977ec681f3Smrg      append(dst, "eye.q");
10983464ebd5Sriastradh      break;
10993464ebd5Sriastradh   case STATE_TEXGEN_OBJECT_S:
11007ec681f3Smrg      append(dst, "object.s");
11013464ebd5Sriastradh      break;
11023464ebd5Sriastradh   case STATE_TEXGEN_OBJECT_T:
11037ec681f3Smrg      append(dst, "object.t");
11043464ebd5Sriastradh      break;
11053464ebd5Sriastradh   case STATE_TEXGEN_OBJECT_R:
11067ec681f3Smrg      append(dst, "object.r");
11073464ebd5Sriastradh      break;
11083464ebd5Sriastradh   case STATE_TEXGEN_OBJECT_Q:
11097ec681f3Smrg      append(dst, "object.q");
11103464ebd5Sriastradh      break;
11113464ebd5Sriastradh   case STATE_TEXENV_COLOR:
11123464ebd5Sriastradh      append(dst, "texenv");
11133464ebd5Sriastradh      break;
1114af69d88dSmrg   case STATE_NUM_SAMPLES:
1115af69d88dSmrg      append(dst, "numsamples");
1116af69d88dSmrg      break;
11173464ebd5Sriastradh   case STATE_DEPTH_RANGE:
11183464ebd5Sriastradh      append(dst, "depth.range");
11193464ebd5Sriastradh      break;
11207ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV:
11217ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV:
11223464ebd5Sriastradh      append(dst, "env");
11233464ebd5Sriastradh      break;
11247ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
11257ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
11267ec681f3Smrg      append(dst, "env.range");
11277ec681f3Smrg      break;
11287ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL:
11297ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL:
11303464ebd5Sriastradh      append(dst, "local");
11313464ebd5Sriastradh      break;
11327ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
11337ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
11347ec681f3Smrg      append(dst, "local.range");
11353464ebd5Sriastradh      break;
11363464ebd5Sriastradh   case STATE_CURRENT_ATTRIB:
11373464ebd5Sriastradh      append(dst, "current");
11383464ebd5Sriastradh      break;
1139af69d88dSmrg   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
1140af69d88dSmrg      append(dst, "currentAttribMaybeVPClamped");
1141af69d88dSmrg      break;
11427ec681f3Smrg   case STATE_NORMAL_SCALE_EYESPACE:
11437ec681f3Smrg      append(dst, "normalScaleEyeSpace");
11447ec681f3Smrg      break;
11453464ebd5Sriastradh   case STATE_NORMAL_SCALE:
11463464ebd5Sriastradh      append(dst, "normalScale");
11473464ebd5Sriastradh      break;
11483464ebd5Sriastradh   case STATE_FOG_PARAMS_OPTIMIZED:
11493464ebd5Sriastradh      append(dst, "fogParamsOptimized");
11503464ebd5Sriastradh      break;
11513464ebd5Sriastradh   case STATE_POINT_SIZE_CLAMPED:
11523464ebd5Sriastradh      append(dst, "pointSizeClamped");
11533464ebd5Sriastradh      break;
11543464ebd5Sriastradh   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
11553464ebd5Sriastradh      append(dst, "lightSpotDirNormalized");
11563464ebd5Sriastradh      break;
11573464ebd5Sriastradh   case STATE_LIGHT_POSITION:
11587ec681f3Smrg      append(dst, "light.position");
11597ec681f3Smrg      break;
11607ec681f3Smrg   case STATE_LIGHT_POSITION_ARRAY:
11617ec681f3Smrg      append(dst, "light.position.array");
11623464ebd5Sriastradh      break;
11633464ebd5Sriastradh   case STATE_LIGHT_POSITION_NORMALIZED:
11643464ebd5Sriastradh      append(dst, "light.position.normalized");
11653464ebd5Sriastradh      break;
11667ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
11677ec681f3Smrg      append(dst, "light.position.normalized.array");
11687ec681f3Smrg      break;
11693464ebd5Sriastradh   case STATE_LIGHT_HALF_VECTOR:
11703464ebd5Sriastradh      append(dst, "lightHalfVector");
11713464ebd5Sriastradh      break;
11723464ebd5Sriastradh   case STATE_PT_SCALE:
11733464ebd5Sriastradh      append(dst, "PTscale");
11743464ebd5Sriastradh      break;
11753464ebd5Sriastradh   case STATE_PT_BIAS:
11763464ebd5Sriastradh      append(dst, "PTbias");
11773464ebd5Sriastradh      break;
11783464ebd5Sriastradh   case STATE_FB_SIZE:
11793464ebd5Sriastradh      append(dst, "FbSize");
11803464ebd5Sriastradh      break;
11813464ebd5Sriastradh   case STATE_FB_WPOS_Y_TRANSFORM:
11823464ebd5Sriastradh      append(dst, "FbWposYTransform");
11833464ebd5Sriastradh      break;
11847ec681f3Smrg   case STATE_FB_PNTC_Y_TRANSFORM:
11857ec681f3Smrg      append(dst, "PntcYTransform");
11867ec681f3Smrg      break;
118701e04c3fSmrg   case STATE_ADVANCED_BLENDING_MODE:
118801e04c3fSmrg      append(dst, "AdvancedBlendingMode");
118901e04c3fSmrg      break;
11907ec681f3Smrg   case STATE_ALPHA_REF:
11917ec681f3Smrg      append(dst, "alphaRef");
11927ec681f3Smrg      break;
11937ec681f3Smrg   case STATE_CLIP_INTERNAL:
11947ec681f3Smrg      append(dst, "clipInternal");
11957ec681f3Smrg      break;
11963464ebd5Sriastradh   default:
11973464ebd5Sriastradh      /* probably STATE_INTERNAL_DRIVER+i (driver private state) */
11983464ebd5Sriastradh      append(dst, "driverState");
11993464ebd5Sriastradh   }
12003464ebd5Sriastradh}
12013464ebd5Sriastradh
12023464ebd5Sriastradhstatic void
12037ec681f3Smrgappend_index(char *dst, GLint index, bool structure)
12043464ebd5Sriastradh{
12053464ebd5Sriastradh   char s[20];
12067ec681f3Smrg   sprintf(s, "[%d]%s", index, structure ? "." : "");
12073464ebd5Sriastradh   append(dst, s);
12083464ebd5Sriastradh}
12093464ebd5Sriastradh
12103464ebd5Sriastradh/**
12113464ebd5Sriastradh * Make a string from the given state vector.
12123464ebd5Sriastradh * For example, return "state.matrix.texture[2].inverse".
12133464ebd5Sriastradh * Use free() to deallocate the string.
12143464ebd5Sriastradh */
12153464ebd5Sriastradhchar *
121601e04c3fSmrg_mesa_program_state_string(const gl_state_index16 state[STATE_LENGTH])
12173464ebd5Sriastradh{
12183464ebd5Sriastradh   char str[1000] = "";
12193464ebd5Sriastradh   char tmp[30];
12203464ebd5Sriastradh
12213464ebd5Sriastradh   append(str, "state.");
12223464ebd5Sriastradh   append_token(str, state[0]);
12233464ebd5Sriastradh
12243464ebd5Sriastradh   switch (state[0]) {
12253464ebd5Sriastradh   case STATE_LIGHT:
12267ec681f3Smrg      append_index(str, state[1], true); /* light number [i]. */
12273464ebd5Sriastradh      append_token(str, state[2]); /* coefficients */
12283464ebd5Sriastradh      break;
12293464ebd5Sriastradh   case STATE_LIGHTMODEL_AMBIENT:
12303464ebd5Sriastradh      break;
12313464ebd5Sriastradh   case STATE_LIGHTMODEL_SCENECOLOR:
12323464ebd5Sriastradh      if (state[1] == 0) {
12333464ebd5Sriastradh         append(str, "lightmodel.front.scenecolor");
12343464ebd5Sriastradh      }
12353464ebd5Sriastradh      else {
12363464ebd5Sriastradh         append(str, "lightmodel.back.scenecolor");
12373464ebd5Sriastradh      }
12383464ebd5Sriastradh      break;
12393464ebd5Sriastradh   case STATE_LIGHTPROD:
12407ec681f3Smrg      append_index(str, state[1], false); /* light number [i] */
12417ec681f3Smrg      append_index(str, state[2], false);
12423464ebd5Sriastradh      break;
12433464ebd5Sriastradh   case STATE_TEXGEN:
12447ec681f3Smrg      append_index(str, state[1], true); /* tex unit [i] */
12453464ebd5Sriastradh      append_token(str, state[2]); /* plane coef */
12463464ebd5Sriastradh      break;
12473464ebd5Sriastradh   case STATE_TEXENV_COLOR:
12487ec681f3Smrg      append_index(str, state[1], true); /* tex unit [i] */
12493464ebd5Sriastradh      append(str, "color");
12503464ebd5Sriastradh      break;
12513464ebd5Sriastradh   case STATE_CLIPPLANE:
12527ec681f3Smrg      append_index(str, state[1], true); /* plane [i] */
12537ec681f3Smrg      append(str, "plane");
12543464ebd5Sriastradh      break;
12553464ebd5Sriastradh   case STATE_MODELVIEW_MATRIX:
12567ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVERSE:
12577ec681f3Smrg   case STATE_MODELVIEW_MATRIX_TRANSPOSE:
12587ec681f3Smrg   case STATE_MODELVIEW_MATRIX_INVTRANS:
12593464ebd5Sriastradh   case STATE_PROJECTION_MATRIX:
12607ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVERSE:
12617ec681f3Smrg   case STATE_PROJECTION_MATRIX_TRANSPOSE:
12627ec681f3Smrg   case STATE_PROJECTION_MATRIX_INVTRANS:
12633464ebd5Sriastradh   case STATE_MVP_MATRIX:
12647ec681f3Smrg   case STATE_MVP_MATRIX_INVERSE:
12657ec681f3Smrg   case STATE_MVP_MATRIX_TRANSPOSE:
12667ec681f3Smrg   case STATE_MVP_MATRIX_INVTRANS:
12673464ebd5Sriastradh   case STATE_TEXTURE_MATRIX:
12687ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVERSE:
12697ec681f3Smrg   case STATE_TEXTURE_MATRIX_TRANSPOSE:
12707ec681f3Smrg   case STATE_TEXTURE_MATRIX_INVTRANS:
12713464ebd5Sriastradh   case STATE_PROGRAM_MATRIX:
12727ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVERSE:
12737ec681f3Smrg   case STATE_PROGRAM_MATRIX_TRANSPOSE:
12747ec681f3Smrg   case STATE_PROGRAM_MATRIX_INVTRANS:
12753464ebd5Sriastradh      {
12763464ebd5Sriastradh         /* state[0] = modelview, projection, texture, etc. */
12773464ebd5Sriastradh         /* state[1] = which texture matrix or program matrix */
12783464ebd5Sriastradh         /* state[2] = first row to fetch */
12793464ebd5Sriastradh         /* state[3] = last row to fetch */
12803464ebd5Sriastradh         const gl_state_index mat = state[0];
12813464ebd5Sriastradh         const GLuint index = (GLuint) state[1];
12823464ebd5Sriastradh         const GLuint firstRow = (GLuint) state[2];
12833464ebd5Sriastradh         const GLuint lastRow = (GLuint) state[3];
12843464ebd5Sriastradh         if (index ||
12857ec681f3Smrg             (mat >= STATE_TEXTURE_MATRIX &&
12867ec681f3Smrg              mat <= STATE_PROGRAM_MATRIX_INVTRANS))
12877ec681f3Smrg            append_index(str, index, true);
12883464ebd5Sriastradh         if (firstRow == lastRow)
12897ec681f3Smrg            sprintf(tmp, "row[%d]", firstRow);
12903464ebd5Sriastradh         else
12917ec681f3Smrg            sprintf(tmp, "row[%d..%d]", firstRow, lastRow);
12923464ebd5Sriastradh         append(str, tmp);
12933464ebd5Sriastradh      }
12943464ebd5Sriastradh      break;
12957ec681f3Smrg   case STATE_LIGHT_ARRAY:
12967ec681f3Smrg   case STATE_LIGHT_ATTENUATION_ARRAY:
12977ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV_ARRAY:
12987ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY:
12997ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV_ARRAY:
13007ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL_ARRAY:
13017ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_FRONT:
13027ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_BACK:
13037ec681f3Smrg   case STATE_LIGHTPROD_ARRAY_TWOSIDE:
13047ec681f3Smrg   case STATE_LIGHT_POSITION_ARRAY:
13057ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED_ARRAY:
13067ec681f3Smrg      sprintf(tmp, "[%d..%d]", state[1], state[1] + state[2] - 1);
13077ec681f3Smrg      append(str, tmp);
13083464ebd5Sriastradh      break;
13097ec681f3Smrg   case STATE_MATERIAL:
13107ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_ENV:
13117ec681f3Smrg   case STATE_FRAGMENT_PROGRAM_LOCAL:
13127ec681f3Smrg   case STATE_VERTEX_PROGRAM_ENV:
13137ec681f3Smrg   case STATE_VERTEX_PROGRAM_LOCAL:
13147ec681f3Smrg   case STATE_CURRENT_ATTRIB:
13157ec681f3Smrg   case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED:
13167ec681f3Smrg   case STATE_LIGHT_SPOT_DIR_NORMALIZED:
13177ec681f3Smrg   case STATE_LIGHT_POSITION:
13187ec681f3Smrg   case STATE_LIGHT_POSITION_NORMALIZED:
13197ec681f3Smrg   case STATE_LIGHT_HALF_VECTOR:
13207ec681f3Smrg   case STATE_CLIP_INTERNAL:
13217ec681f3Smrg      append_index(str, state[1], false);
13223464ebd5Sriastradh      break;
13237ec681f3Smrg   case STATE_POINT_SIZE:
13247ec681f3Smrg   case STATE_POINT_ATTENUATION:
13253464ebd5Sriastradh   case STATE_FOG_PARAMS:
13263464ebd5Sriastradh   case STATE_FOG_COLOR:
1327af69d88dSmrg   case STATE_NUM_SAMPLES:
13283464ebd5Sriastradh   case STATE_DEPTH_RANGE:
13297ec681f3Smrg   case STATE_NORMAL_SCALE_EYESPACE:
13303464ebd5Sriastradh   case STATE_NORMAL_SCALE:
13317ec681f3Smrg   case STATE_FOG_PARAMS_OPTIMIZED:
13327ec681f3Smrg   case STATE_POINT_SIZE_CLAMPED:
13337ec681f3Smrg   case STATE_PT_SCALE:
13347ec681f3Smrg   case STATE_PT_BIAS:
13357ec681f3Smrg   case STATE_FB_SIZE:
13367ec681f3Smrg   case STATE_FB_WPOS_Y_TRANSFORM:
13377ec681f3Smrg   case STATE_TCS_PATCH_VERTICES_IN:
13387ec681f3Smrg   case STATE_TES_PATCH_VERTICES_IN:
13397ec681f3Smrg   case STATE_ADVANCED_BLENDING_MODE:
13407ec681f3Smrg   case STATE_ALPHA_REF:
13417ec681f3Smrg      break;
13427ec681f3Smrg   case STATE_NOT_STATE_VAR:
13437ec681f3Smrg      append(str, "not_state");
13443464ebd5Sriastradh      break;
13453464ebd5Sriastradh   default:
13463464ebd5Sriastradh      _mesa_problem(NULL, "Invalid state in _mesa_program_state_string");
13473464ebd5Sriastradh      break;
13483464ebd5Sriastradh   }
13493464ebd5Sriastradh
135001e04c3fSmrg   return strdup(str);
13513464ebd5Sriastradh}
13523464ebd5Sriastradh
13533464ebd5Sriastradh
13543464ebd5Sriastradh/**
13553464ebd5Sriastradh * Loop over all the parameters in a parameter list.  If the parameter
13563464ebd5Sriastradh * is a GL state reference, look up the current value of that state
13573464ebd5Sriastradh * variable and put it into the parameter's Value[4] array.
13583464ebd5Sriastradh * Other parameter types never change or are explicitly set by the user
13593464ebd5Sriastradh * with glUniform() or glProgramParameter(), etc.
13603464ebd5Sriastradh * This would be called at glBegin time.
13613464ebd5Sriastradh */
13623464ebd5Sriastradhvoid
13633464ebd5Sriastradh_mesa_load_state_parameters(struct gl_context *ctx,
13643464ebd5Sriastradh                            struct gl_program_parameter_list *paramList)
13653464ebd5Sriastradh{
13663464ebd5Sriastradh   if (!paramList)
13673464ebd5Sriastradh      return;
13683464ebd5Sriastradh
13697ec681f3Smrg   int last = paramList->LastStateVarIndex;
13707ec681f3Smrg
13717ec681f3Smrg   for (int i = paramList->FirstStateVarIndex; i <= last; i++) {
13727ec681f3Smrg      unsigned pvo = paramList->Parameters[i].ValueOffset;
13737ec681f3Smrg      fetch_state(ctx, paramList->Parameters[i].StateIndexes,
13747ec681f3Smrg                  paramList->ParameterValues + pvo);
13757ec681f3Smrg   }
13767ec681f3Smrg}
13777ec681f3Smrg
13787ec681f3Smrgvoid
13797ec681f3Smrg_mesa_upload_state_parameters(struct gl_context *ctx,
13807ec681f3Smrg                              struct gl_program_parameter_list *paramList,
13817ec681f3Smrg                              uint32_t *dst)
13827ec681f3Smrg{
13837ec681f3Smrg   int last = paramList->LastStateVarIndex;
13847ec681f3Smrg
13857ec681f3Smrg   for (int i = paramList->FirstStateVarIndex; i <= last; i++) {
13867ec681f3Smrg      unsigned pvo = paramList->Parameters[i].ValueOffset;
13877ec681f3Smrg      fetch_state(ctx, paramList->Parameters[i].StateIndexes,
13887ec681f3Smrg                  (gl_constant_value*)(dst + pvo));
13897ec681f3Smrg   }
13907ec681f3Smrg}
13917ec681f3Smrg
13927ec681f3Smrg/* Merge consecutive state vars into one for the state vars that allow
13937ec681f3Smrg * multiple vec4s.
13947ec681f3Smrg *
13957ec681f3Smrg * This should be done after shader compilation, so that drivers don't
13967ec681f3Smrg * have to deal with multi-slot state parameters in their backends.
13977ec681f3Smrg * It's only meant to optimize _mesa_load/upload_state_parameters.
13987ec681f3Smrg */
13997ec681f3Smrgvoid
14007ec681f3Smrg_mesa_optimize_state_parameters(struct gl_constants *consts,
14017ec681f3Smrg                                struct gl_program_parameter_list *list)
14027ec681f3Smrg{
14037ec681f3Smrg   for (int first_param = list->FirstStateVarIndex;
14047ec681f3Smrg        first_param < (int)list->NumParameters; first_param++) {
14057ec681f3Smrg      int last_param = first_param;
14067ec681f3Smrg      int param_diff = 0;
14077ec681f3Smrg
14087ec681f3Smrg      switch (list->Parameters[first_param].StateIndexes[0]) {
14097ec681f3Smrg      case STATE_MODELVIEW_MATRIX:
14107ec681f3Smrg      case STATE_MODELVIEW_MATRIX_INVERSE:
14117ec681f3Smrg      case STATE_MODELVIEW_MATRIX_TRANSPOSE:
14127ec681f3Smrg      case STATE_MODELVIEW_MATRIX_INVTRANS:
14137ec681f3Smrg      case STATE_PROJECTION_MATRIX:
14147ec681f3Smrg      case STATE_PROJECTION_MATRIX_INVERSE:
14157ec681f3Smrg      case STATE_PROJECTION_MATRIX_TRANSPOSE:
14167ec681f3Smrg      case STATE_PROJECTION_MATRIX_INVTRANS:
14177ec681f3Smrg      case STATE_MVP_MATRIX:
14187ec681f3Smrg      case STATE_MVP_MATRIX_INVERSE:
14197ec681f3Smrg      case STATE_MVP_MATRIX_TRANSPOSE:
14207ec681f3Smrg      case STATE_MVP_MATRIX_INVTRANS:
14217ec681f3Smrg      case STATE_TEXTURE_MATRIX:
14227ec681f3Smrg      case STATE_TEXTURE_MATRIX_INVERSE:
14237ec681f3Smrg      case STATE_TEXTURE_MATRIX_TRANSPOSE:
14247ec681f3Smrg      case STATE_TEXTURE_MATRIX_INVTRANS:
14257ec681f3Smrg      case STATE_PROGRAM_MATRIX:
14267ec681f3Smrg      case STATE_PROGRAM_MATRIX_INVERSE:
14277ec681f3Smrg      case STATE_PROGRAM_MATRIX_TRANSPOSE:
14287ec681f3Smrg      case STATE_PROGRAM_MATRIX_INVTRANS:
14297ec681f3Smrg         /* Skip unaligned state vars. */
14307ec681f3Smrg         if (list->Parameters[first_param].Size % 4)
14317ec681f3Smrg            break;
14327ec681f3Smrg
14337ec681f3Smrg         /* Search for adjacent state vars that refer to adjacent rows. */
14347ec681f3Smrg         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
14357ec681f3Smrg            if (list->Parameters[i].StateIndexes[0] ==
14367ec681f3Smrg                list->Parameters[i - 1].StateIndexes[0] &&
14377ec681f3Smrg                list->Parameters[i].StateIndexes[1] ==
14387ec681f3Smrg                list->Parameters[i - 1].StateIndexes[1] &&
14397ec681f3Smrg                list->Parameters[i].StateIndexes[2] ==         /* FirstRow */
14407ec681f3Smrg                list->Parameters[i - 1].StateIndexes[3] + 1 && /* LastRow + 1 */
14417ec681f3Smrg                list->Parameters[i].Size == 4) {
14427ec681f3Smrg               last_param = i;
14437ec681f3Smrg               continue;
14447ec681f3Smrg            }
14457ec681f3Smrg            break; /* The adjacent state var is incompatible. */
14467ec681f3Smrg         }
14477ec681f3Smrg         if (last_param > first_param) {
14487ec681f3Smrg            int first_vec = list->Parameters[first_param].StateIndexes[2];
14497ec681f3Smrg            int last_vec = list->Parameters[last_param].StateIndexes[3];
14507ec681f3Smrg
14517ec681f3Smrg            assert(first_vec < last_vec);
14527ec681f3Smrg            assert(last_vec - first_vec == last_param - first_param);
14537ec681f3Smrg
14547ec681f3Smrg            /* Update LastRow. */
14557ec681f3Smrg            list->Parameters[first_param].StateIndexes[3] = last_vec;
14567ec681f3Smrg            list->Parameters[first_param].Size = (last_vec - first_vec + 1) * 4;
14577ec681f3Smrg
14587ec681f3Smrg            param_diff = last_param - first_param;
14597ec681f3Smrg         }
14607ec681f3Smrg         break;
14617ec681f3Smrg
14627ec681f3Smrg      case STATE_LIGHT:
14637ec681f3Smrg         /* Skip trimmed state vars. (this shouldn't occur though) */
14647ec681f3Smrg         if (list->Parameters[first_param].Size !=
14657ec681f3Smrg             _mesa_program_state_value_size(list->Parameters[first_param].StateIndexes))
14667ec681f3Smrg            break;
14677ec681f3Smrg
14687ec681f3Smrg         /* Search for light attributes that are adjacent in memory. */
14697ec681f3Smrg         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
14707ec681f3Smrg            if (list->Parameters[i].StateIndexes[0] == STATE_LIGHT &&
14717ec681f3Smrg                /* Consecutive attributes of the same light: */
14727ec681f3Smrg                ((list->Parameters[i].StateIndexes[1] ==
14737ec681f3Smrg                  list->Parameters[i - 1].StateIndexes[1] &&
14747ec681f3Smrg                  list->Parameters[i].StateIndexes[2] ==
14757ec681f3Smrg                  list->Parameters[i - 1].StateIndexes[2] + 1) ||
14767ec681f3Smrg                 /* Consecutive attributes between 2 lights: */
14777ec681f3Smrg                 /* SPOT_CUTOFF should have only 1 component, which isn't true
14787ec681f3Smrg                  * with unpacked uniform storage. */
14797ec681f3Smrg                 (consts->PackedDriverUniformStorage &&
14807ec681f3Smrg                  list->Parameters[i].StateIndexes[1] ==
14817ec681f3Smrg                  list->Parameters[i - 1].StateIndexes[1] + 1 &&
14827ec681f3Smrg                  list->Parameters[i].StateIndexes[2] == STATE_AMBIENT &&
14837ec681f3Smrg                  list->Parameters[i - 1].StateIndexes[2] == STATE_SPOT_CUTOFF))) {
14847ec681f3Smrg               last_param = i;
14857ec681f3Smrg               continue;
14867ec681f3Smrg            }
14877ec681f3Smrg            break; /* The adjacent state var is incompatible. */
14887ec681f3Smrg         }
14897ec681f3Smrg         if (last_param > first_param) {
14907ec681f3Smrg            /* Convert the state var to STATE_LIGHT_ARRAY. */
14917ec681f3Smrg            list->Parameters[first_param].StateIndexes[0] = STATE_LIGHT_ARRAY;
14927ec681f3Smrg            /* Set the offset in floats. */
14937ec681f3Smrg            list->Parameters[first_param].StateIndexes[1] =
14947ec681f3Smrg               list->Parameters[first_param].StateIndexes[1] * /* light index */
14957ec681f3Smrg               sizeof(struct gl_light_uniforms) / 4 +
14967ec681f3Smrg               (list->Parameters[first_param].StateIndexes[2] - STATE_AMBIENT) * 4;
14977ec681f3Smrg
14987ec681f3Smrg            /* Set the real size in floats that we will upload (memcpy). */
14997ec681f3Smrg            list->Parameters[first_param].StateIndexes[2] =
15007ec681f3Smrg               _mesa_program_state_value_size(list->Parameters[last_param].StateIndexes) +
15017ec681f3Smrg               list->Parameters[last_param].ValueOffset -
15027ec681f3Smrg               list->Parameters[first_param].ValueOffset;
15037ec681f3Smrg
15047ec681f3Smrg            /* Set the allocated size, which can be aligned to 4 components. */
15057ec681f3Smrg            list->Parameters[first_param].Size =
15067ec681f3Smrg               list->Parameters[last_param].Size +
15077ec681f3Smrg               list->Parameters[last_param].ValueOffset -
15087ec681f3Smrg               list->Parameters[first_param].ValueOffset;
15097ec681f3Smrg
15107ec681f3Smrg            param_diff = last_param - first_param;
15117ec681f3Smrg            break; /* all done */
15127ec681f3Smrg         }
15137ec681f3Smrg
15147ec681f3Smrg         /* We were not able to convert light attributes to STATE_LIGHT_ARRAY.
15157ec681f3Smrg          * Another occuring pattern is light attentuation vectors placed back
15167ec681f3Smrg          * to back. Find them.
15177ec681f3Smrg          */
15187ec681f3Smrg         if (list->Parameters[first_param].StateIndexes[2] == STATE_ATTENUATION) {
15197ec681f3Smrg            for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
15207ec681f3Smrg               if (list->Parameters[i].StateIndexes[0] == STATE_LIGHT &&
15217ec681f3Smrg                   /* Consecutive light: */
15227ec681f3Smrg                   list->Parameters[i].StateIndexes[1] ==
15237ec681f3Smrg                   list->Parameters[i - 1].StateIndexes[1] + 1 &&
15247ec681f3Smrg                   /* Same attribute: */
15257ec681f3Smrg                   list->Parameters[i].StateIndexes[2] ==
15267ec681f3Smrg                   list->Parameters[i - 1].StateIndexes[2]) {
15277ec681f3Smrg                  last_param = i;
15287ec681f3Smrg                  continue;
15297ec681f3Smrg               }
15307ec681f3Smrg               break; /* The adjacent state var is incompatible. */
15317ec681f3Smrg            }
15327ec681f3Smrg            if (last_param > first_param) {
15337ec681f3Smrg               param_diff = last_param - first_param;
15347ec681f3Smrg
15357ec681f3Smrg               /* Convert the state var to STATE_LIGHT_ATTENUATION_ARRAY. */
15367ec681f3Smrg               list->Parameters[first_param].StateIndexes[0] =
15377ec681f3Smrg                  STATE_LIGHT_ATTENUATION_ARRAY;
15387ec681f3Smrg               /* Keep the light index the same. */
15397ec681f3Smrg               /* Set the number of lights. */
15407ec681f3Smrg               unsigned size = param_diff + 1;
15417ec681f3Smrg               list->Parameters[first_param].StateIndexes[2] = size;
15427ec681f3Smrg               list->Parameters[first_param].Size = size * 4;
15437ec681f3Smrg               break; /* all done */
15447ec681f3Smrg            }
15457ec681f3Smrg         }
15467ec681f3Smrg         break;
15477ec681f3Smrg
15487ec681f3Smrg      case STATE_VERTEX_PROGRAM_ENV:
15497ec681f3Smrg      case STATE_VERTEX_PROGRAM_LOCAL:
15507ec681f3Smrg      case STATE_FRAGMENT_PROGRAM_ENV:
15517ec681f3Smrg      case STATE_FRAGMENT_PROGRAM_LOCAL:
15527ec681f3Smrg         if (list->Parameters[first_param].Size != 4)
15537ec681f3Smrg            break;
15547ec681f3Smrg
15557ec681f3Smrg         /* Search for adjacent mergeable state vars. */
15567ec681f3Smrg         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
15577ec681f3Smrg            if (list->Parameters[i].StateIndexes[0] ==
15587ec681f3Smrg                list->Parameters[i - 1].StateIndexes[0] &&
15597ec681f3Smrg                list->Parameters[i].StateIndexes[1] ==
15607ec681f3Smrg                list->Parameters[i - 1].StateIndexes[1] + 1 &&
15617ec681f3Smrg                list->Parameters[i].Size == 4) {
15627ec681f3Smrg               last_param = i;
15637ec681f3Smrg               continue;
15647ec681f3Smrg            }
15657ec681f3Smrg            break; /* The adjacent state var is incompatible. */
15667ec681f3Smrg         }
15677ec681f3Smrg         if (last_param > first_param) {
15687ec681f3Smrg            /* Set STATE_xxx_RANGE. */
15697ec681f3Smrg            STATIC_ASSERT(STATE_VERTEX_PROGRAM_ENV + 1 ==
15707ec681f3Smrg                          STATE_VERTEX_PROGRAM_ENV_ARRAY);
15717ec681f3Smrg            STATIC_ASSERT(STATE_VERTEX_PROGRAM_LOCAL + 1 ==
15727ec681f3Smrg                          STATE_VERTEX_PROGRAM_LOCAL_ARRAY);
15737ec681f3Smrg            STATIC_ASSERT(STATE_FRAGMENT_PROGRAM_ENV + 1 ==
15747ec681f3Smrg                          STATE_FRAGMENT_PROGRAM_ENV_ARRAY);
15757ec681f3Smrg            STATIC_ASSERT(STATE_FRAGMENT_PROGRAM_LOCAL + 1 ==
15767ec681f3Smrg                          STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY);
15777ec681f3Smrg            list->Parameters[first_param].StateIndexes[0]++;
15787ec681f3Smrg
15797ec681f3Smrg            param_diff = last_param - first_param;
15807ec681f3Smrg
15817ec681f3Smrg            /* Set the size. */
15827ec681f3Smrg            unsigned size = param_diff + 1;
15837ec681f3Smrg            list->Parameters[first_param].StateIndexes[2] = size;
15847ec681f3Smrg            list->Parameters[first_param].Size = size * 4;
15857ec681f3Smrg         }
15867ec681f3Smrg         break;
15877ec681f3Smrg
15887ec681f3Smrg      case STATE_LIGHTPROD: {
15897ec681f3Smrg         if (list->Parameters[first_param].Size != 4)
15907ec681f3Smrg            break;
15917ec681f3Smrg
15927ec681f3Smrg         gl_state_index16 state = STATE_NOT_STATE_VAR;
15937ec681f3Smrg         unsigned num_lights = 0;
15947ec681f3Smrg
15957ec681f3Smrg         for (unsigned state_iter = STATE_LIGHTPROD_ARRAY_FRONT;
15967ec681f3Smrg              state_iter <= STATE_LIGHTPROD_ARRAY_TWOSIDE; state_iter++) {
15977ec681f3Smrg            unsigned num_attribs, base_attrib, attrib_incr;
15987ec681f3Smrg
15997ec681f3Smrg            if (state_iter == STATE_LIGHTPROD_ARRAY_FRONT)  {
16007ec681f3Smrg               num_attribs = 3;
16017ec681f3Smrg               base_attrib = MAT_ATTRIB_FRONT_AMBIENT;
16027ec681f3Smrg               attrib_incr = 2;
16037ec681f3Smrg            } else if (state_iter == STATE_LIGHTPROD_ARRAY_BACK) {
16047ec681f3Smrg               num_attribs = 3;
16057ec681f3Smrg               base_attrib = MAT_ATTRIB_BACK_AMBIENT;
16067ec681f3Smrg               attrib_incr = 2;
16077ec681f3Smrg            } else if (state_iter == STATE_LIGHTPROD_ARRAY_TWOSIDE) {
16087ec681f3Smrg               num_attribs = 6;
16097ec681f3Smrg               base_attrib = MAT_ATTRIB_FRONT_AMBIENT;
16107ec681f3Smrg               attrib_incr = 1;
16117ec681f3Smrg            }
16127ec681f3Smrg
16137ec681f3Smrg            /* Find all attributes for one light. */
16147ec681f3Smrg            while (first_param + (num_lights + 1) * num_attribs <=
16157ec681f3Smrg                   list->NumParameters &&
16167ec681f3Smrg                   (state == STATE_NOT_STATE_VAR || state == state_iter)) {
16177ec681f3Smrg               unsigned i = 0, base = first_param + num_lights * num_attribs;
16187ec681f3Smrg
16197ec681f3Smrg               /* Consecutive light indices: */
16207ec681f3Smrg               if (list->Parameters[first_param].StateIndexes[1] + num_lights ==
16217ec681f3Smrg                   list->Parameters[base].StateIndexes[1]) {
16227ec681f3Smrg                  for (i = 0; i < num_attribs; i++) {
16237ec681f3Smrg                     if (list->Parameters[base + i].StateIndexes[0] ==
16247ec681f3Smrg                         STATE_LIGHTPROD &&
16257ec681f3Smrg                         list->Parameters[base + i].Size == 4 &&
16267ec681f3Smrg                         /* Equal light indices: */
16277ec681f3Smrg                         list->Parameters[base + i].StateIndexes[1] ==
16287ec681f3Smrg                         list->Parameters[base + 0].StateIndexes[1] &&
16297ec681f3Smrg                         /* Consecutive attributes: */
16307ec681f3Smrg                         list->Parameters[base + i].StateIndexes[2] ==
16317ec681f3Smrg                         base_attrib + i * attrib_incr)
16327ec681f3Smrg                        continue;
16337ec681f3Smrg                     break;
16347ec681f3Smrg                  }
16357ec681f3Smrg               }
16367ec681f3Smrg               if (i == num_attribs) {
16377ec681f3Smrg                  /* Accept all parameters for merging. */
16387ec681f3Smrg                  state = state_iter;
16397ec681f3Smrg                  last_param = base + num_attribs - 1;
16407ec681f3Smrg                  num_lights++;
16417ec681f3Smrg               } else {
16427ec681f3Smrg                  break;
16437ec681f3Smrg               }
16447ec681f3Smrg            }
16457ec681f3Smrg         }
16467ec681f3Smrg
16477ec681f3Smrg         if (last_param > first_param) {
16487ec681f3Smrg            param_diff = last_param - first_param;
16497ec681f3Smrg
16507ec681f3Smrg            list->Parameters[first_param].StateIndexes[0] = state;
16517ec681f3Smrg            list->Parameters[first_param].StateIndexes[2] = num_lights;
16527ec681f3Smrg            list->Parameters[first_param].Size = (param_diff + 1) * 4;
16537ec681f3Smrg         }
16547ec681f3Smrg         break;
16557ec681f3Smrg      }
16567ec681f3Smrg
16577ec681f3Smrg      case STATE_LIGHT_POSITION:
16587ec681f3Smrg      case STATE_LIGHT_POSITION_NORMALIZED:
16597ec681f3Smrg         if (list->Parameters[first_param].Size != 4)
16607ec681f3Smrg            break;
16617ec681f3Smrg
16627ec681f3Smrg         for (int i = first_param + 1; i < (int)list->NumParameters; i++) {
16637ec681f3Smrg            if (list->Parameters[i].StateIndexes[0] ==
16647ec681f3Smrg                list->Parameters[i - 1].StateIndexes[0] &&
16657ec681f3Smrg                /* Consecutive light: */
16667ec681f3Smrg                list->Parameters[i].StateIndexes[1] ==
16677ec681f3Smrg                list->Parameters[i - 1].StateIndexes[1] + 1) {
16687ec681f3Smrg               last_param = i;
16697ec681f3Smrg               continue;
16707ec681f3Smrg            }
16717ec681f3Smrg            break; /* The adjacent state var is incompatible. */
16727ec681f3Smrg         }
16737ec681f3Smrg         if (last_param > first_param) {
16747ec681f3Smrg            param_diff = last_param - first_param;
16757ec681f3Smrg
16767ec681f3Smrg            /* Convert the state var to STATE_LIGHT_POSITION_*ARRAY. */
16777ec681f3Smrg            STATIC_ASSERT(STATE_LIGHT_POSITION + 1 ==
16787ec681f3Smrg                          STATE_LIGHT_POSITION_ARRAY);
16797ec681f3Smrg            STATIC_ASSERT(STATE_LIGHT_POSITION_NORMALIZED + 1 ==
16807ec681f3Smrg                          STATE_LIGHT_POSITION_NORMALIZED_ARRAY);
16817ec681f3Smrg            list->Parameters[first_param].StateIndexes[0]++;
16827ec681f3Smrg            /* Keep the light index the same. */
16837ec681f3Smrg            unsigned size = param_diff + 1;
16847ec681f3Smrg            /* Set the number of lights. */
16857ec681f3Smrg            list->Parameters[first_param].StateIndexes[2] = size;
16867ec681f3Smrg            list->Parameters[first_param].Size = size * 4;
16877ec681f3Smrg         }
16887ec681f3Smrg      }
16897ec681f3Smrg
16907ec681f3Smrg      if (param_diff) {
16917ec681f3Smrg         /* Update the name. */
16927ec681f3Smrg         free((void*)list->Parameters[first_param].Name);
16937ec681f3Smrg         list->Parameters[first_param].Name =
16947ec681f3Smrg            _mesa_program_state_string(list->Parameters[first_param].StateIndexes);
16957ec681f3Smrg
16967ec681f3Smrg         /* Free names that we are going to overwrite. */
16977ec681f3Smrg         for (int i = first_param + 1; i <= last_param; i++)
16987ec681f3Smrg            free((char*)list->Parameters[i].Name);
16997ec681f3Smrg
17007ec681f3Smrg         /* Remove the merged state vars. */
17017ec681f3Smrg         if (last_param + 1 < list->NumParameters) {
17027ec681f3Smrg            memmove(&list->Parameters[first_param + 1],
17037ec681f3Smrg                    &list->Parameters[last_param + 1],
17047ec681f3Smrg                    sizeof(list->Parameters[0]) *
17057ec681f3Smrg                    (list->NumParameters - last_param - 1));
17067ec681f3Smrg         }
17077ec681f3Smrg         list->NumParameters -= param_diff;
17083464ebd5Sriastradh      }
17093464ebd5Sriastradh   }
17107ec681f3Smrg
17117ec681f3Smrg   _mesa_recompute_parameter_bounds(list);
17123464ebd5Sriastradh}
1713