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