spirv2dxil: Handle aliasing/overlapping UBO/SSBO variables

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27280>
This commit is contained in:
Jesse Natalie
2024-01-25 10:01:28 -08:00
committed by Marge Bot
parent 4833126b40
commit 98ec98d08f

View File

@@ -937,6 +937,55 @@ lower_bit_size_callback(const nir_instr *instr, void *data)
}
}
static bool
merge_ubos_and_ssbos(nir_shader *nir)
{
bool progress = false;
nir_foreach_variable_with_modes_safe(var, nir, nir_var_mem_ubo | nir_var_mem_ssbo) {
nir_variable *other_var = NULL;
nir_foreach_variable_with_modes(var2, nir, var->data.mode) {
if (var->data.descriptor_set == var2->data.descriptor_set &&
var->data.binding == var2->data.binding) {
other_var = var2;
break;
}
}
if (!other_var)
continue;
progress = true;
/* Merge types */
if (var->type != other_var->type) {
/* Pick the larger array size */
uint32_t desc_array_size = 1;
if (glsl_type_is_array(var->type))
desc_array_size = glsl_get_aoa_size(var->type);
if (glsl_type_is_array(other_var->type))
desc_array_size = MAX2(desc_array_size, glsl_get_aoa_size(other_var->type));
const glsl_type *struct_type = glsl_without_array(var->type);
if (var->data.mode == nir_var_mem_ubo) {
/* Pick the larger struct type; doesn't matter for ssbos */
uint32_t size = glsl_get_explicit_size(struct_type, false);
const glsl_type *other_type = glsl_without_array(other_var->type);
if (glsl_get_explicit_size(other_type, false) > size)
struct_type = other_type;
}
var->type = glsl_array_type(struct_type, desc_array_size, 0);
/* An ssbo is non-writeable if all aliased vars are non-writeable */
if (var->data.mode == nir_var_mem_ssbo)
var->data.access &= ~(other_var->data.access & ACCESS_NON_WRITEABLE);
exec_node_remove(&other_var->node);
}
}
nir_shader_preserve_all_metadata(nir);
return progress;
}
void
dxil_spirv_nir_passes(nir_shader *nir,
const struct dxil_spirv_runtime_conf *conf,
@@ -1153,6 +1202,7 @@ dxil_spirv_nir_passes(nir_shader *nir,
NIR_PASS_V(nir, nir_remove_dead_variables,
nir_var_uniform | nir_var_shader_in | nir_var_shader_out,
NULL);
NIR_PASS_V(nir, merge_ubos_and_ssbos);
if (nir->info.stage == MESA_SHADER_FRAGMENT) {
dxil_sort_ps_outputs(nir);