[Mesa-dev] [PATCH 14/14] mesa: Rewrite shader-based texture image state updates.

Ilia Mirkin imirkin at alum.mit.edu
Fri Apr 25 16:26:37 PDT 2014


On Thu, Apr 24, 2014 at 8:50 PM, Eric Anholt <eric at anholt.net> wrote:
> Instead of walking 6 shader stages for each of the 96 combined texture
> image units, now we just walk the samplers used in each shader stage.
>
> With cairo-perf-trace on Xephyr with glamor, I'm seeing a -6.50518% +/-
> 2.55601% effect on runtime (n=22) since the "drop _EnabledUnits" change.
> No significant performance difference on an apitrace of minecraft (n=442).
> ---
>  src/mesa/main/texstate.c | 122 ++++++++++++++++++++++++++++-------------------
>  1 file changed, 73 insertions(+), 49 deletions(-)
>
> diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c
> index 0082caf..3a7e227 100644
> --- a/src/mesa/main/texstate.c
> +++ b/src/mesa/main/texstate.c
> @@ -515,68 +515,92 @@ update_texgen(struct gl_context *ctx)
>     }
>  }
>
> +static struct gl_texture_object *
> +update_single_program_texture(struct gl_context *ctx, struct gl_program *prog,
> +                              int s)
> +{
> +   gl_texture_index target_index;
> +   struct gl_texture_unit *texUnit;
> +   struct gl_texture_object *texObj;
> +   int unit;
> +
> +   if (!(prog->SamplersUsed & (1 << s)))
> +      return NULL;
> +
> +   unit = prog->SamplerUnits[s];
> +   texUnit = &ctx->Texture.Unit[unit];
> +
> +   /* Note: If more than one bit was set in TexturesUsed[unit], then we should
> +    * have had the draw call rejected already.  From the GL 4.4 specification,
> +    * section 7.10 ("Samplers"):
> +    *
> +    *     "It is not allowed to have variables of different sampler types
> +    *      pointing to the same texture image unit within a program
> +    *      object. This situation can only be detected at the next rendering
> +    *      command issued which triggers shader invocations, and an
> +    *      INVALID_OPERATION error will then be generated."
> +    */
> +   target_index = ffs(prog->TexturesUsed[unit]) - 1;
> +   texObj = texUnit->CurrentTex[target_index];
> +
> +   struct gl_sampler_object *sampler = texUnit->Sampler ?
> +      texUnit->Sampler : &texObj->Sampler;
> +
> +   if (likely(texObj)) {
> +      if (_mesa_is_texture_complete(texObj, sampler))
> +         return texObj;
> +
> +      _mesa_test_texobj_completeness(ctx, texObj);
> +      if (_mesa_is_texture_complete(texObj, sampler))
> +         return texObj;
> +   }
> +
> +   /* If we've reached this point, we didn't find a complete texture of the
> +    * shader's target.  From the GL 4.4 core specification, section 11.1.3.5
> +    * ("Texture Access"):
> +    *
> +    *     "If a sampler is used in a shader and the sampler’s associated
> +    *      texture is not complete, as defined in section 8.17, (0, 0, 0, 1)
> +    *      will be returned for a non-shadow sampler and 0 for a shadow
> +    *      sampler."
> +    *
> +    * Mesa implements this by creating a hidden texture object with a pixel of
> +    * that value.
> +    */
> +   texObj = _mesa_get_fallback_texture(ctx, target_index);
> +   assert(texObj);
> +
> +   return texObj;
> +}
> +
>  static void
>  update_program_texture_state(struct gl_context *ctx, struct gl_program **prog,
>                               BITSET_WORD *enabled_texture_units)
>  {
> -   GLuint unit;
>     int i;
>
> -   for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) {
> -      struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
> -      GLbitfield enabledTargets = 0x0;
> -      GLuint texIndex;
> -
> -      for (i = 0; i < MESA_SHADER_STAGES; i++) {
> -         if (prog[i])
> -            enabledTargets |= prog[i]->TexturesUsed[unit];
> -      }
> +   for (i = 0; i < MESA_SHADER_STAGES; i++) {
> +      int s;
>
> -      if (enabledTargets == 0x0) {
> -         /* neither vertex nor fragment processing uses this unit */
> +      if (!prog[i])
>           continue;
> -      }
> -
> -      for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
> -         if (enabledTargets & (1 << texIndex)) {
> -            struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
> -            struct gl_sampler_object *sampler = texUnit->Sampler ?
> -               texUnit->Sampler : &texObj->Sampler;
> -
> -            if (!_mesa_is_texture_complete(texObj, sampler)) {
> -               _mesa_test_texobj_completeness(ctx, texObj);
> -            }
> -            if (_mesa_is_texture_complete(texObj, sampler)) {
> -               _mesa_reference_texobj(&texUnit->_Current, texObj);
> -               break;
> -            }
> -         }
> -      }
>
> -      if (texIndex == NUM_TEXTURE_TARGETS) {
> -         /* If we get here it means the shader is expecting a texture
> -          * object, but there isn't one (or it's incomplete).  Use the
> -          * fallback texture.
> -          */
> +      /* We can't only do the shifting trick as the loop condition because if
> +       * sampler 31 is active, the next iteration tries to shift by 32, which is
> +       * undefined.
> +       */
> +      for (s = 0; s < MAX_SAMPLERS && (1 << s) <= prog[i]->SamplersUsed; s++) {

I could be confused, but are you trying to walk over all set bits of
SamplersUsed? You can do this with something like u_bit_scan() which
basically does

tmp = prog[i]->SamplersUsed;
while (tmp) {
  s = ffs(tmp) - 1;
  tmp &= ~(1 << s);
  ...
}

This should avoid pointless iteration when there are just a few bits
set. If the expectation is that 1..n bits are all going to be set,
then this provides little advantage.

  -ilia

>           struct gl_texture_object *texObj;
> -         gl_texture_index texTarget;
> -
> -         texTarget = (gl_texture_index) (ffs(enabledTargets) - 1);
> -         texObj = _mesa_get_fallback_texture(ctx, texTarget);
>
> -         assert(texObj);
> -         if (!texObj) {
> -            /* invalid fallback texture: don't enable the texture unit */
> -            continue;
> +         texObj = update_single_program_texture(ctx, prog[i], s);
> +         if (texObj) {
> +            int unit = prog[i]->SamplerUnits[s];
> +            _mesa_reference_texobj(&ctx->Texture.Unit[unit]._Current, texObj);
> +            BITSET_SET(enabled_texture_units, unit);
> +            ctx->Texture._MaxEnabledTexImageUnit =
> +               MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit);
>           }
> -
> -         _mesa_reference_texobj(&texUnit->_Current, texObj);
>        }
> -
> -      /* if we get here, we know this texture unit is enabled */
> -      BITSET_SET(enabled_texture_units, unit);
> -      ctx->Texture._MaxEnabledTexImageUnit =
> -         MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit);
>     }
>
>     if (prog[MESA_SHADER_FRAGMENT]) {
> --
> 1.9.2
>
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>


More information about the mesa-dev mailing list