diff --git a/src/compiler/glsl/glsl_to_nir.cpp b/src/compiler/glsl/glsl_to_nir.cpp index 6c7395aad8f..7ad246990b8 100644 --- a/src/compiler/glsl/glsl_to_nir.cpp +++ b/src/compiler/glsl/glsl_to_nir.cpp @@ -2528,13 +2528,8 @@ nir_visitor::visit(ir_dereference_variable *ir) i++; } - nir_variable_mode mode = - glsl_contains_opaque(ir->variable_referenced()->type) && - ir->variable_referenced()->data.mode == ir_var_function_in ? - nir_var_uniform : nir_var_function_temp; - this->deref = nir_build_deref_cast(&b, nir_load_param(&b, i), - mode, ir->type, 0); + nir_var_function_temp, ir->type, 0); return; } diff --git a/src/compiler/nir/nir_functions.c b/src/compiler/nir/nir_functions.c index cb5af9592c0..9f3cc5eea68 100644 --- a/src/compiler/nir/nir_functions.c +++ b/src/compiler/nir/nir_functions.c @@ -53,6 +53,30 @@ function_ends_in_jump(nir_function_impl *impl) return nir_block_ends_in_jump(last_block); } +/* A cast is used to deref function in/out params. However the bindless + * textures spec allows both uniforms and functions temps to be passed to a + * function param defined the same way. To deal with this we need to update + * this when we inline and know what variable mode we are dealing with. + */ +static void +fixup_cast_deref_mode(nir_deref_instr *deref) +{ + nir_deref_instr *parent = nir_src_as_deref(deref->parent); + if (parent && parent->modes & nir_var_uniform && + deref->modes & nir_var_function_temp) { + deref->modes |= nir_var_uniform; + deref->modes ^= nir_var_function_temp; + + nir_foreach_use(use, &deref->def) { + if (nir_src_parent_instr(use)->type != nir_instr_type_deref) + continue; + + /* Recurse into children */ + fixup_cast_deref_mode(nir_instr_as_deref(nir_src_parent_instr(use))); + } + } +} + void nir_inline_function_impl(struct nir_builder *b, const nir_function_impl *impl, @@ -68,6 +92,17 @@ nir_inline_function_impl(struct nir_builder *b, switch (instr->type) { case nir_instr_type_deref: { nir_deref_instr *deref = nir_instr_as_deref(instr); + + /* Note: This shouldn't change the mode of anything but the + * replaced nir_intrinsic_load_param intrinsics handled later in + * this switch table. Any incorrect modes should have already been + * detected by previous nir_vaidate calls. + */ + if (deref->deref_type == nir_deref_type_cast) { + fixup_cast_deref_mode(deref); + break; + } + if (deref->deref_type != nir_deref_type_var) break;