mesa: merge STATE_LIGHTPROD parameters
authorMarek Olšák <marek.olsak@amd.com>
Sat, 5 Dec 2020 21:00:14 +0000 (16:00 -0500)
committerMarge Bot <eric+marge@anholt.net>
Fri, 26 Feb 2021 23:38:02 +0000 (23:38 +0000)
This decreases the CPU time spent in fetch_state.

Reviewed-by: Zoltán Böszörményi <zboszor@gmail.com>
Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8850>

src/mesa/main/ffvertex_prog.c
src/mesa/program/prog_statevars.c
src/mesa/program/prog_statevars.h

index 5d43178..525b098 100644 (file)
@@ -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;
 
index ff85dab..ad53ed1 100644 (file)
@@ -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) {
index ae1acf8..281696b 100644 (file)
@@ -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,