mesa: faster validation of sampler unit mapping for SSO

Code was inspired from _mesa_update_shader_textures_used

However unlike _mesa_update_shader_textures_used that only check for a single
stage, it will check all stages.

It avoids to loop on all uniforms, only active samplers are checked.

For my use case: high FS frequency switches with few samplers.
Perf event (relative to nouveau_dri.so) goes from 5.01% to 1.68% for
the _mesa_sampler_uniforms_pipeline_are_valid function.

Signed-off-by: Gregory Hainaut <gregory.hainaut@gmail.com>
Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
This commit is contained in:
Gregory Hainaut 2016-06-24 10:07:02 +02:00 committed by Timothy Arceri
parent cb728df967
commit 6a524c76f5

View file

@ -1068,29 +1068,30 @@ _mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline)
* - The number of active samplers in the program exceeds the * - The number of active samplers in the program exceeds the
* maximum number of texture image units allowed." * maximum number of texture image units allowed."
*/ */
GLbitfield mask;
GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
struct gl_shader *shader;
unsigned active_samplers = 0; unsigned active_samplers = 0;
const struct gl_shader_program **shProg = const struct gl_shader_program **shProg =
(const struct gl_shader_program **) pipeline->CurrentProgram; (const struct gl_shader_program **) pipeline->CurrentProgram;
const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
memset(unit_types, 0, sizeof(unit_types)); memset(TexturesUsed, 0, sizeof(TexturesUsed));
for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) { for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) {
if (!shProg[idx]) if (!shProg[idx])
continue; continue;
for (unsigned i = 0; i < shProg[idx]->NumUniformStorage; i++) { shader = shProg[idx]->_LinkedShaders[idx];
const struct gl_uniform_storage *const storage = if (!shader || !shader->Program)
&shProg[idx]->UniformStorage[i];
if (!storage->type->is_sampler())
continue; continue;
active_samplers++; mask = shader->Program->SamplersUsed;
while (mask) {
const unsigned count = MAX2(1, storage->array_elements); const int s = u_bit_scan(&mask);
for (unsigned j = 0; j < count; j++) { GLuint unit = shader->SamplerUnits[s];
const unsigned unit = storage->storage[j].i; GLuint tgt = shader->SamplerTargets[s];
/* FIXME: Samplers are initialized to 0 and Mesa doesn't do a /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a
* great job of eliminating unused uniforms currently so for now * great job of eliminating unused uniforms currently so for now
@ -1099,27 +1100,19 @@ _mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline)
if (unit == 0) if (unit == 0)
continue; continue;
/* The types of the samplers associated with a particular texture if (TexturesUsed[unit] & ~(1 << tgt)) {
* unit must be an exact match. Page 74 (page 89 of the PDF) of
* the OpenGL 3.3 core spec says:
*
* "It is not allowed to have variables of different sampler
* types pointing to the same texture image unit within a
* program object."
*/
if (unit_types[unit] == NULL) {
unit_types[unit] = storage->type;
} else if (unit_types[unit] != storage->type) {
pipeline->InfoLog = pipeline->InfoLog =
ralloc_asprintf(pipeline, ralloc_asprintf(pipeline,
"Texture unit %d is accessed both as %s " "Program %d: "
"and %s", "Texture unit %d is accessed with 2 different types",
unit, unit_types[unit]->name, shProg[idx]->Name, unit);
storage->type->name);
return false; return false;
} }
TexturesUsed[unit] |= (1 << tgt);
} }
}
active_samplers += shader->num_samplers;
} }
if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) { if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) {