From 6a97deb88aa715af9760cf3c7ca0c1ff76e4f325 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 24 Apr 2014 00:57:54 -0700 Subject: [PATCH] mesa: Rewrite shader-based texture image state updates. 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). Reviewed-by: Kenneth Graunke --- 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 0082caf2b1e..3a7e2273f90 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++) { 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]) { -- 2.30.2