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 <e...@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@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev