From a1a08a58025a6026aae0f73b67451198f5befb42 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 22 Apr 2020 15:47:28 -0500 Subject: [PATCH] nir/opt_deref: Remove certain sampler type casts The SPIR-V parser sometimes generates casts from specific sampler types like sampler2D to the bare sampler type. This results in a cast which causes heartburn for drivers but is harmless to remove. cc: mesa-stable@lists.freedesktop.org Reviewed-by: Dave Airlie Part-of: --- src/compiler/nir/nir_deref.c | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/compiler/nir/nir_deref.c b/src/compiler/nir/nir_deref.c index aa841223a3b..e06fd07aeb2 100644 --- a/src/compiler/nir/nir_deref.c +++ b/src/compiler/nir/nir_deref.c @@ -753,6 +753,42 @@ nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl) return state.progress; } +static void +nir_deref_instr_fixup_child_types(nir_deref_instr *parent) +{ + nir_foreach_use(use, &parent->dest.ssa) { + if (use->parent_instr->type != nir_instr_type_deref) + continue; + + nir_deref_instr *child = nir_instr_as_deref(use->parent_instr); + switch (child->deref_type) { + case nir_deref_type_var: + unreachable("nir_deref_type_var cannot be a child"); + + case nir_deref_type_array: + case nir_deref_type_array_wildcard: + child->type = glsl_get_array_element(parent->type); + break; + + case nir_deref_type_ptr_as_array: + child->type = parent->type; + break; + + case nir_deref_type_struct: + child->type = glsl_get_struct_field(parent->type, + child->strct.index); + break; + + case nir_deref_type_cast: + /* We stop the recursion here */ + continue; + } + + /* Recurse into children */ + nir_deref_instr_fixup_child_types(child); + } +} + static bool is_trivial_array_deref_cast(nir_deref_instr *cast) { @@ -800,6 +836,44 @@ opt_remove_cast_cast(nir_deref_instr *cast) return true; } +static bool +opt_remove_sampler_cast(nir_deref_instr *cast) +{ + assert(cast->deref_type == nir_deref_type_cast); + nir_deref_instr *parent = nir_src_as_deref(cast->parent); + if (parent == NULL) + return false; + + /* Strip both types down to their non-array type and bail if there are any + * discrepancies in array lengths. + */ + const struct glsl_type *parent_type = parent->type; + const struct glsl_type *cast_type = cast->type; + while (glsl_type_is_array(parent_type) && glsl_type_is_array(cast_type)) { + if (glsl_get_length(parent_type) != glsl_get_length(cast_type)) + return false; + parent_type = glsl_get_array_element(parent_type); + cast_type = glsl_get_array_element(cast_type); + } + + if (glsl_type_is_array(parent_type) || glsl_type_is_array(cast_type)) + return false; + + if (!glsl_type_is_sampler(parent_type) || + cast_type != glsl_bare_sampler_type()) + return false; + + /* We're a cast from a more detailed sampler type to a bare sampler */ + nir_ssa_def_rewrite_uses(&cast->dest.ssa, + nir_src_for_ssa(&parent->dest.ssa)); + nir_instr_remove(&cast->instr); + + /* Recursively crawl the deref tree and clean up types */ + nir_deref_instr_fixup_child_types(parent); + + return true; +} + /** * Is this casting a struct to a contained struct. * struct a { struct b field0 }; @@ -839,6 +913,9 @@ opt_deref_cast(nir_builder *b, nir_deref_instr *cast) if (opt_replace_struct_wrapper_cast(b, cast)) return true; + if (opt_remove_sampler_cast(cast)) + return true; + progress = opt_remove_cast_cast(cast); if (!is_trivial_deref_cast(cast)) return progress; -- 2.30.2