[Mesa-dev] [PATCH 13/14] mesa: Split the shader texture update logic from fixed function.

Marek Olšák maraeo at gmail.com
Fri Apr 25 04:19:06 PDT 2014


Have you considered disabling creating the fallback textures for
hardware which can return the correct constant for a texture fetch if
a texture isn't bouńd?

Marek

On Fri, Apr 25, 2014 at 2:50 AM, Eric Anholt <eric at anholt.net> wrote:
> I want to avoid walking the entire long array texture image units, but the
> obvious way to do so means walking program samplers, and thus hitting the
> units in a random order.
>
> This change replaces the previous behavior of only setting up the fallback
> texture for a fragment shader with setting up the fallback texture for any
> shader that's missing a complete texture of the right target in its unit.
> ---
>  src/mesa/main/texstate.c | 250 ++++++++++++++++++++++++++++++-----------------
>  1 file changed, 160 insertions(+), 90 deletions(-)
>
> diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c
> index 24469da..0082caf 100644
> --- a/src/mesa/main/texstate.c
> +++ b/src/mesa/main/texstate.c
> @@ -40,7 +40,7 @@
>  #include "teximage.h"
>  #include "texstate.h"
>  #include "mtypes.h"
> -
> +#include "bitset.h"
>
>
>  /**
> @@ -515,79 +515,28 @@ update_texgen(struct gl_context *ctx)
>     }
>  }
>
> -/**
> - * \note This routine refers to derived texture matrix values to
> - * compute the ENABLE_TEXMAT flags, but is only called on
> - * _NEW_TEXTURE.  On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT
> - * flags are updated by _mesa_update_texture_matrices, above.
> - *
> - * \param ctx GL context.
> - */
>  static void
> -update_texture_state( struct gl_context *ctx )
> +update_program_texture_state(struct gl_context *ctx, struct gl_program **prog,
> +                             BITSET_WORD *enabled_texture_units)
>  {
>     GLuint unit;
> -   struct gl_program *prog[MESA_SHADER_STAGES];
> -   GLbitfield enabledFragUnits = 0x0;
>     int i;
>
> -   for (i = 0; i < MESA_SHADER_STAGES; i++) {
> -      if (ctx->_Shader->CurrentProgram[i] &&
> -          ctx->_Shader->CurrentProgram[i]->LinkStatus) {
> -         prog[i] = ctx->_Shader->CurrentProgram[i]->_LinkedShaders[i]->Program;
> -      } else {
> -         if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled)
> -            prog[i] = &ctx->FragmentProgram.Current->Base;
> -         else
> -            prog[i] = NULL;
> -      }
> -   }
> -
> -   /* TODO: only set this if there are actual changes */
> -   ctx->NewState |= _NEW_TEXTURE;
> -
> -   ctx->Texture._GenFlags = 0x0;
> -   ctx->Texture._TexMatEnabled = 0x0;
> -   ctx->Texture._TexGenEnabled = 0x0;
> -   ctx->Texture._MaxEnabledTexImageUnit = -1;
> -
> -   /*
> -    * Update texture unit state.
> -    */
>     for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) {
>        struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
> -      GLbitfield enabledTargetsByStage[MESA_SHADER_STAGES];
>        GLbitfield enabledTargets = 0x0;
>        GLuint texIndex;
>
> -      /* Get the bitmask of texture target enables.
> -       * enableBits will be a mask of the TEXTURE_*_BIT flags indicating
> -       * which texture targets are enabled (fixed function) or referenced
> -       * by a fragment program/program.  When multiple flags are set, we'll
> -       * settle on the one with highest priority (see below).
> -       */
>        for (i = 0; i < MESA_SHADER_STAGES; i++) {
>           if (prog[i])
> -            enabledTargetsByStage[i] = prog[i]->TexturesUsed[unit];
> -         else if (i == MESA_SHADER_FRAGMENT)
> -            enabledTargetsByStage[i] = texUnit->Enabled;
> -         else
> -            enabledTargetsByStage[i] = 0;
> -         enabledTargets |= enabledTargetsByStage[i];
> +            enabledTargets |= prog[i]->TexturesUsed[unit];
>        }
>
>        if (enabledTargets == 0x0) {
> -         _mesa_reference_texobj(&texUnit->_Current, NULL);
>           /* neither vertex nor fragment processing uses this unit */
>           continue;
>        }
>
> -      /* Look for the highest priority texture target that's enabled (or used
> -       * by the vert/frag shaders) and "complete".  That's the one we'll use
> -       * for texturing.
> -       *
> -       * Note that the TEXTURE_x_INDEX values are in high to low priority.
> -       */
>        for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
>           if (enabledTargets & (1 << texIndex)) {
>              struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
> @@ -605,52 +554,173 @@ update_texture_state( struct gl_context *ctx )
>        }
>
>        if (texIndex == NUM_TEXTURE_TARGETS) {
> -         if (prog[MESA_SHADER_FRAGMENT]) {
> -            /* 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.
> -             */
> -            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;
> -            }
> -
> -            _mesa_reference_texobj(&texUnit->_Current, texObj);
> -         }
> -         else {
> -            /* fixed-function: texture unit is really disabled */
> -            _mesa_reference_texobj(&texUnit->_Current, NULL);
> +         /* 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.
> +          */
> +         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;
>           }
> +
> +         _mesa_reference_texobj(&texUnit->_Current, texObj);
>        }
>
>        /* if we get here, we know this texture unit is enabled */
> -      ctx->Texture._MaxEnabledTexImageUnit = unit;
> -
> -      if (enabledTargetsByStage[MESA_SHADER_FRAGMENT])
> -         enabledFragUnits |= (1 << unit);
> -
> -      if (!prog[MESA_SHADER_FRAGMENT])
> -         update_tex_combine(ctx, texUnit);
> +      BITSET_SET(enabled_texture_units, unit);
> +      ctx->Texture._MaxEnabledTexImageUnit =
> +         MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit);
>     }
>
> -
> -   /* Determine which texture coordinate sets are actually needed */
>     if (prog[MESA_SHADER_FRAGMENT]) {
>        const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
> -      ctx->Texture._EnabledCoordUnits
> -         = (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) &
> +      ctx->Texture._EnabledCoordUnits |=
> +         (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) &
>           coordMask;
>     }
> -   else {
> -      ctx->Texture._EnabledCoordUnits = enabledFragUnits;
> +}
> +
> +static void
> +update_ff_texture_state(struct gl_context *ctx,
> +                        BITSET_WORD *enabled_texture_units)
> +{
> +   int unit;
> +
> +   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
> +      struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
> +      GLuint texIndex;
> +
> +      if (texUnit->Enabled == 0x0)
> +         continue;
> +
> +      /* If a shader already dictated what texture target was used for this
> +       * unit, just go along with it.
> +       */
> +      if (BITSET_TEST(enabled_texture_units, unit))
> +         continue;
> +
> +      /* From the GL 4.4 compat specification, section 16.2 ("Texture Application"):
> +       *
> +       *     "Texturing is enabled or disabled using the generic Enable and
> +       *      Disable commands, respectively, with the symbolic constants
> +       *      TEXTURE_1D, TEXTURE_2D, TEXTURE_RECTANGLE, TEXTURE_3D, or
> +       *      TEXTURE_CUBE_MAP to enable the one-, two-, rectangular,
> +       *      three-dimensional, or cube map texture, respectively. If more
> +       *      than one of these textures is enabled, the first one enabled
> +       *      from the following list is used:
> +       *
> +       *      • cube map texture
> +       *      • three-dimensional texture
> +       *      • rectangular texture
> +       *      • two-dimensional texture
> +       *      • one-dimensional texture"
> +       *
> +       * Note that the TEXTURE_x_INDEX values are in high to low priority.
> +       * Also:
> +       *
> +       *     "If a texture unit is disabled or has an invalid or incomplete
> +       *      texture (as defined in section 8.17) bound to it, then blending
> +       *      is disabled for that texture unit. If the texture environment
> +       *      for a given enabled texture unit references a disabled texture
> +       *      unit, or an invalid or incomplete texture that is bound to
> +       *      another unit, then the results of texture blending are
> +       *      undefined."
> +       */
> +      for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
> +         if (texUnit->Enabled & (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)
> +         continue;
> +
> +      /* 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);
> +
> +      ctx->Texture._EnabledCoordUnits |= 1 << unit;
> +
> +      update_tex_combine(ctx, texUnit);
> +   }
> +}
> +
> +/**
> + * \note This routine refers to derived texture matrix values to
> + * compute the ENABLE_TEXMAT flags, but is only called on
> + * _NEW_TEXTURE.  On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT
> + * flags are updated by _mesa_update_texture_matrices, above.
> + *
> + * \param ctx GL context.
> + */
> +static void
> +update_texture_state( struct gl_context *ctx )
> +{
> +   struct gl_program *prog[MESA_SHADER_STAGES];
> +   int i;
> +   int old_max_unit = ctx->Texture._MaxEnabledTexImageUnit;
> +   BITSET_DECLARE(enabled_texture_units, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
> +
> +   for (i = 0; i < MESA_SHADER_STAGES; i++) {
> +      if (ctx->_Shader->CurrentProgram[i] &&
> +          ctx->_Shader->CurrentProgram[i]->LinkStatus) {
> +         prog[i] = ctx->_Shader->CurrentProgram[i]->_LinkedShaders[i]->Program;
> +      } else {
> +         if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled)
> +            prog[i] = &ctx->FragmentProgram.Current->Base;
> +         else
> +            prog[i] = NULL;
> +      }
> +   }
> +
> +   /* TODO: only set this if there are actual changes */
> +   ctx->NewState |= _NEW_TEXTURE;
> +
> +   ctx->Texture._GenFlags = 0x0;
> +   ctx->Texture._TexMatEnabled = 0x0;
> +   ctx->Texture._TexGenEnabled = 0x0;
> +   ctx->Texture._MaxEnabledTexImageUnit = -1;
> +   ctx->Texture._EnabledCoordUnits = 0x0;
> +
> +   memset(&enabled_texture_units, 0, sizeof(enabled_texture_units));
> +
> +   /* First, walk over our programs pulling in all the textures for them.
> +    * Programs dictate specific texture targets to be enabled, and for a draw
> +    * call to be valid they can't conflict about which texture targets are
> +    * used.
> +    */
> +   update_program_texture_state(ctx, prog, enabled_texture_units);
> +
> +   /* Also pull in any textures necessary for fixed function fragment shading.
> +    */
> +   if (!prog[MESA_SHADER_FRAGMENT])
> +      update_ff_texture_state(ctx, enabled_texture_units);
> +
> +   /* Now, clear out the _Current of any disabled texture units. */
> +   for (i = 0; i <= ctx->Texture._MaxEnabledTexImageUnit; i++) {
> +      if (!BITSET_TEST(enabled_texture_units, i))
> +         _mesa_reference_texobj(&ctx->Texture.Unit[i]._Current, NULL);
> +   }
> +   for (i = ctx->Texture._MaxEnabledTexImageUnit + 1; i <= old_max_unit; i++) {
> +      _mesa_reference_texobj(&ctx->Texture.Unit[i]._Current, NULL);
>     }
>
>     if (!prog[MESA_SHADER_FRAGMENT] || !prog[MESA_SHADER_VERTEX])
> --
> 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