diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c index 5d431785d83..525b0988903 100644 --- a/src/mesa/main/ffvertex_prog.c +++ b/src/mesa/main/ffvertex_prog.c @@ -1107,6 +1107,28 @@ static void build_lighting( struct tnl_program *p ) return; } + /* Declare light products first to place them sequentially next to each + * other for optimal constant uploads. + */ + struct ureg lightprod_front[MAX_LIGHTS][3]; + struct ureg lightprod_back[MAX_LIGHTS][3]; + + for (i = 0; i < MAX_LIGHTS; i++) { + if (p->state->unit[i].light_enabled) { + lightprod_front[i][0] = get_lightprod(p, i, 0, STATE_AMBIENT); + if (twoside) + lightprod_back[i][0] = get_lightprod(p, i, 1, STATE_AMBIENT); + + lightprod_front[i][1] = get_lightprod(p, i, 0, STATE_DIFFUSE); + if (twoside) + lightprod_back[i][1] = get_lightprod(p, i, 1, STATE_DIFFUSE); + + lightprod_front[i][2] = get_lightprod(p, i, 0, STATE_SPECULAR); + if (twoside) + lightprod_back[i][2] = get_lightprod(p, i, 1, STATE_SPECULAR); + } + } + for (i = 0; i < MAX_LIGHTS; i++) { if (p->state->unit[i].light_enabled) { struct ureg half = undef; @@ -1171,9 +1193,9 @@ static void build_lighting( struct tnl_program *p ) /* Front face lighting: */ { - struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT); - struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE); - struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR); + struct ureg ambient = lightprod_front[i][0]; + struct ureg diffuse = lightprod_front[i][1]; + struct ureg specular = lightprod_front[i][2]; struct ureg res0, res1; GLuint mask0, mask1; @@ -1226,9 +1248,9 @@ static void build_lighting( struct tnl_program *p ) /* Back face lighting: */ if (twoside) { - struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT); - struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE); - struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR); + struct ureg ambient = lightprod_back[i][0]; + struct ureg diffuse = lightprod_back[i][1]; + struct ureg specular = lightprod_back[i][2]; struct ureg res0, res1; GLuint mask0, mask1; diff --git a/src/mesa/program/prog_statevars.c b/src/mesa/program/prog_statevars.c index ff85dabfb1b..ad53ed1ac8e 100644 --- a/src/mesa/program/prog_statevars.c +++ b/src/mesa/program/prog_statevars.c @@ -178,6 +178,84 @@ fetch_state(struct gl_context *ctx, const gl_state_index16 state[], value[3] = ctx->Light.Material.Attrib[index][3]; return; } + case STATE_LIGHTPROD_ARRAY_FRONT: { + const unsigned first_light = state[1]; + const unsigned num_lights = state[2]; + + for (unsigned i = 0; i < num_lights; i++) { + unsigned light = first_light + i; + + for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT; + attrib <= MAT_ATTRIB_FRONT_SPECULAR; attrib += 2) { + for (int chan = 0; chan < 3; chan++) { + /* We want offset to access out of bounds into the following + * Diffuse and Specular fields. This is guaranteed to work + * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely + * on this memory layout. + */ + unsigned offset = (attrib / 2) * 4 + chan; + *value++ = + (&ctx->Light.LightSource[light].Ambient[0])[offset] * + ctx->Light.Material.Attrib[attrib][chan]; + } + /* [3] = material alpha */ + *value++ = ctx->Light.Material.Attrib[attrib][3]; + } + } + return; + } + case STATE_LIGHTPROD_ARRAY_BACK: { + const unsigned first_light = state[1]; + const unsigned num_lights = state[2]; + + for (unsigned i = 0; i < num_lights; i++) { + unsigned light = first_light + i; + + for (unsigned attrib = MAT_ATTRIB_BACK_AMBIENT; + attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib += 2) { + for (int chan = 0; chan < 3; chan++) { + /* We want offset to access out of bounds into the following + * Diffuse and Specular fields. This is guaranteed to work + * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely + * on this memory layout. + */ + unsigned offset = (attrib / 2) * 4 + chan; + *value++ = + (&ctx->Light.LightSource[light].Ambient[0])[offset] * + ctx->Light.Material.Attrib[attrib][chan]; + } + /* [3] = material alpha */ + *value++ = ctx->Light.Material.Attrib[attrib][3]; + } + } + return; + } + case STATE_LIGHTPROD_ARRAY_TWOSIDE: { + const unsigned first_light = state[1]; + const unsigned num_lights = state[2]; + + for (unsigned i = 0; i < num_lights; i++) { + unsigned light = first_light + i; + + for (unsigned attrib = MAT_ATTRIB_FRONT_AMBIENT; + attrib <= MAT_ATTRIB_BACK_SPECULAR; attrib++) { + for (int chan = 0; chan < 3; chan++) { + /* We want offset to access out of bounds into the following + * Diffuse and Specular fields. This is guaranteed to work + * because STATE_LIGHT and STATE_LIGHT_ATTRIBS also rely + * on this memory layout. + */ + unsigned offset = (attrib / 2) * 4 + chan; + *value++ = + (&ctx->Light.LightSource[light].Ambient[0])[offset] * + ctx->Light.Material.Attrib[attrib][chan]; + } + /* [3] = material alpha */ + *value++ = ctx->Light.Material.Attrib[attrib][3]; + } + } + return; + } case STATE_TEXGEN: { /* state[1] is the texture unit */ @@ -698,6 +776,9 @@ _mesa_program_state_flags(const gl_state_index16 state[STATE_LENGTH]) return _NEW_MATERIAL | _NEW_CURRENT_ATTRIB; case STATE_LIGHTPROD: + case STATE_LIGHTPROD_ARRAY_FRONT: + case STATE_LIGHTPROD_ARRAY_BACK: + case STATE_LIGHTPROD_ARRAY_TWOSIDE: case STATE_LIGHTMODEL_SCENECOLOR: /* these can be affected by glColor when colormaterial mode is used */ return _NEW_LIGHT_CONSTANTS | _NEW_MATERIAL | _NEW_CURRENT_ATTRIB; @@ -846,6 +927,15 @@ append_token(char *dst, gl_state_index k) case STATE_LIGHTPROD: append(dst, "lightprod"); break; + case STATE_LIGHTPROD_ARRAY_FRONT: + append(dst, "lightprod.array.front"); + break; + case STATE_LIGHTPROD_ARRAY_BACK: + append(dst, "lightprod.array.back"); + break; + case STATE_LIGHTPROD_ARRAY_TWOSIDE: + append(dst, "lightprod.array.twoside"); + break; case STATE_TEXGEN: append(dst, "texgen"); break; @@ -1162,6 +1252,9 @@ _mesa_program_state_string(const gl_state_index16 state[STATE_LENGTH]) case STATE_FRAGMENT_PROGRAM_LOCAL_ARRAY: case STATE_VERTEX_PROGRAM_ENV_ARRAY: case STATE_VERTEX_PROGRAM_LOCAL_ARRAY: + case STATE_LIGHTPROD_ARRAY_FRONT: + case STATE_LIGHTPROD_ARRAY_BACK: + case STATE_LIGHTPROD_ARRAY_TWOSIDE: sprintf(tmp, "[%d..%d]", state[1], state[1] + state[2] - 1); append(str, tmp); break; @@ -1409,6 +1502,75 @@ _mesa_optimize_state_parameters(struct gl_constants *consts, list->Parameters[first_param].Size = size * 4; } break; + + case STATE_LIGHTPROD: { + if (list->Parameters[first_param].Size != 4) + break; + + gl_state_index16 state = STATE_NOT_STATE_VAR; + unsigned num_lights = 0; + + for (unsigned state_iter = STATE_LIGHTPROD_ARRAY_FRONT; + state_iter <= STATE_LIGHTPROD_ARRAY_TWOSIDE; state_iter++) { + unsigned num_attribs, base_attrib, attrib_incr; + + if (state_iter == STATE_LIGHTPROD_ARRAY_FRONT) { + num_attribs = 3; + base_attrib = MAT_ATTRIB_FRONT_AMBIENT; + attrib_incr = 2; + } else if (state_iter == STATE_LIGHTPROD_ARRAY_BACK) { + num_attribs = 3; + base_attrib = MAT_ATTRIB_BACK_AMBIENT; + attrib_incr = 2; + } else if (state_iter == STATE_LIGHTPROD_ARRAY_TWOSIDE) { + num_attribs = 6; + base_attrib = MAT_ATTRIB_FRONT_AMBIENT; + attrib_incr = 1; + } + + /* Find all attributes for one light. */ + while (first_param + (num_lights + 1) * num_attribs <= + list->NumParameters && + (state == STATE_NOT_STATE_VAR || state == state_iter)) { + unsigned i = 0, base = first_param + num_lights * num_attribs; + + /* Consecutive light indices: */ + if (list->Parameters[first_param].StateIndexes[1] + num_lights == + list->Parameters[base].StateIndexes[1]) { + for (i = 0; i < num_attribs; i++) { + if (list->Parameters[base + i].StateIndexes[0] == + STATE_LIGHTPROD && + list->Parameters[base + i].Size == 4 && + /* Equal light indices: */ + list->Parameters[base + i].StateIndexes[1] == + list->Parameters[base + 0].StateIndexes[1] && + /* Consecutive attributes: */ + list->Parameters[base + i].StateIndexes[2] == + base_attrib + i * attrib_incr) + continue; + break; + } + } + if (i == num_attribs) { + /* Accept all parameters for merging. */ + state = state_iter; + last_param = base + num_attribs - 1; + num_lights++; + } else { + break; + } + } + } + + if (last_param > first_param) { + param_diff = last_param - first_param; + + list->Parameters[first_param].StateIndexes[0] = state; + list->Parameters[first_param].StateIndexes[2] = num_lights; + list->Parameters[first_param].Size = (param_diff + 1) * 4; + } + break; + } } if (param_diff) { diff --git a/src/mesa/program/prog_statevars.h b/src/mesa/program/prog_statevars.h index ae1acf81d62..281696bba61 100644 --- a/src/mesa/program/prog_statevars.h +++ b/src/mesa/program/prog_statevars.h @@ -60,6 +60,9 @@ typedef enum gl_state_index_ { STATE_LIGHTMODEL_AMBIENT, STATE_LIGHTMODEL_SCENECOLOR, STATE_LIGHTPROD, + STATE_LIGHTPROD_ARRAY_FRONT, /* multiple lights, only front faces */ + STATE_LIGHTPROD_ARRAY_BACK, /* multiple lights, only back faces */ + STATE_LIGHTPROD_ARRAY_TWOSIDE, /* multiple lights, both sides */ STATE_TEXGEN, STATE_TEXENV_COLOR,