nir: add support for forced sampler indirect loop unrolling
Some drivers don't support these indirects and therefore require loop unrolling if a shader uses a loop induction variable to access a sampler array. Here we add a new nir shader compiler option that drivers can set, this will be the equivalent of the EmitNoIndirectSampler setting used in the GLSL IR unrolling pass. Reviewed-by: Emma Anholt <emma@anholt.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16543>
This commit is contained in:
parent
cb50fe7110
commit
ff8ddcb23e
|
@ -3578,6 +3578,11 @@ typedef struct nir_shader_compiler_options {
|
||||||
* vectorized IO can pack more varyings when linking. */
|
* vectorized IO can pack more varyings when linking. */
|
||||||
bool linker_ignore_precision;
|
bool linker_ignore_precision;
|
||||||
|
|
||||||
|
/* Specifies if indirect sampler array access will trigger forced loop
|
||||||
|
* unrolling.
|
||||||
|
*/
|
||||||
|
bool force_indirect_unrolling_sampler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies which type of indirectly accessed variables should force
|
* Specifies which type of indirectly accessed variables should force
|
||||||
* loop unrolling.
|
* loop unrolling.
|
||||||
|
@ -5312,7 +5317,8 @@ void nir_live_ssa_defs_impl(nir_function_impl *impl);
|
||||||
const BITSET_WORD *nir_get_live_ssa_defs(nir_cursor cursor, void *mem_ctx);
|
const BITSET_WORD *nir_get_live_ssa_defs(nir_cursor cursor, void *mem_ctx);
|
||||||
|
|
||||||
void nir_loop_analyze_impl(nir_function_impl *impl,
|
void nir_loop_analyze_impl(nir_function_impl *impl,
|
||||||
nir_variable_mode indirect_mask);
|
nir_variable_mode indirect_mask,
|
||||||
|
bool force_unroll_sampler_indirect);
|
||||||
|
|
||||||
bool nir_ssa_defs_interfere(nir_ssa_def *a, nir_ssa_def *b);
|
bool nir_ssa_defs_interfere(nir_ssa_def *a, nir_ssa_def *b);
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,8 @@ nir_find_inlinable_uniforms(nir_shader *shader)
|
||||||
|
|
||||||
nir_foreach_function(function, shader) {
|
nir_foreach_function(function, shader) {
|
||||||
if (function->impl) {
|
if (function->impl) {
|
||||||
nir_metadata_require(function->impl, nir_metadata_loop_analysis, nir_var_all);
|
nir_metadata_require(function->impl, nir_metadata_loop_analysis,
|
||||||
|
nir_var_all, false);
|
||||||
|
|
||||||
foreach_list_typed(nir_cf_node, node, node, &function->impl->body)
|
foreach_list_typed(nir_cf_node, node, node, &function->impl->body)
|
||||||
process_node(node, NULL, uni_offsets, &num_offsets);
|
process_node(node, NULL, uni_offsets, &num_offsets);
|
||||||
|
|
|
@ -77,6 +77,7 @@ typedef struct {
|
||||||
|
|
||||||
nir_variable_mode indirect_mask;
|
nir_variable_mode indirect_mask;
|
||||||
|
|
||||||
|
bool force_unroll_sampler_indirect;
|
||||||
} loop_info_state;
|
} loop_info_state;
|
||||||
|
|
||||||
static nir_loop_variable *
|
static nir_loop_variable *
|
||||||
|
@ -601,6 +602,7 @@ find_array_access_via_induction(loop_info_state *state,
|
||||||
*array_index_out = array_index;
|
*array_index_out = array_index;
|
||||||
|
|
||||||
nir_deref_instr *parent = nir_deref_instr_parent(d);
|
nir_deref_instr *parent = nir_deref_instr_parent(d);
|
||||||
|
|
||||||
if (glsl_type_is_array_or_matrix(parent->type)) {
|
if (glsl_type_is_array_or_matrix(parent->type)) {
|
||||||
return glsl_get_length(parent->type);
|
return glsl_get_length(parent->type);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1208,7 +1210,8 @@ find_trip_count(loop_info_state *state, unsigned execution_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
force_unroll_array_access(loop_info_state *state, nir_deref_instr *deref)
|
force_unroll_array_access(loop_info_state *state, nir_deref_instr *deref,
|
||||||
|
bool contains_sampler)
|
||||||
{
|
{
|
||||||
unsigned array_size = find_array_access_via_induction(state, deref, NULL);
|
unsigned array_size = find_array_access_via_induction(state, deref, NULL);
|
||||||
if (array_size) {
|
if (array_size) {
|
||||||
|
@ -1221,6 +1224,9 @@ force_unroll_array_access(loop_info_state *state, nir_deref_instr *deref)
|
||||||
|
|
||||||
if (nir_deref_mode_must_be(deref, state->indirect_mask))
|
if (nir_deref_mode_must_be(deref, state->indirect_mask))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (contains_sampler && state->force_unroll_sampler_indirect)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1230,6 +1236,22 @@ static bool
|
||||||
force_unroll_heuristics(loop_info_state *state, nir_block *block)
|
force_unroll_heuristics(loop_info_state *state, nir_block *block)
|
||||||
{
|
{
|
||||||
nir_foreach_instr(instr, block) {
|
nir_foreach_instr(instr, block) {
|
||||||
|
if (instr->type == nir_instr_type_tex) {
|
||||||
|
nir_tex_instr *tex_instr = nir_instr_as_tex(instr);
|
||||||
|
int sampler_idx =
|
||||||
|
nir_tex_instr_src_index(tex_instr,
|
||||||
|
nir_tex_src_sampler_deref);
|
||||||
|
|
||||||
|
|
||||||
|
if (sampler_idx >= 0) {
|
||||||
|
nir_deref_instr *deref =
|
||||||
|
nir_instr_as_deref(tex_instr->src[sampler_idx].src.ssa->parent_instr);
|
||||||
|
if (force_unroll_array_access(state, deref, true))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (instr->type != nir_instr_type_intrinsic)
|
if (instr->type != nir_instr_type_intrinsic)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1242,12 +1264,14 @@ force_unroll_heuristics(loop_info_state *state, nir_block *block)
|
||||||
intrin->intrinsic == nir_intrinsic_store_deref ||
|
intrin->intrinsic == nir_intrinsic_store_deref ||
|
||||||
intrin->intrinsic == nir_intrinsic_copy_deref) {
|
intrin->intrinsic == nir_intrinsic_copy_deref) {
|
||||||
if (force_unroll_array_access(state,
|
if (force_unroll_array_access(state,
|
||||||
nir_src_as_deref(intrin->src[0])))
|
nir_src_as_deref(intrin->src[0]),
|
||||||
|
false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (intrin->intrinsic == nir_intrinsic_copy_deref &&
|
if (intrin->intrinsic == nir_intrinsic_copy_deref &&
|
||||||
force_unroll_array_access(state,
|
force_unroll_array_access(state,
|
||||||
nir_src_as_deref(intrin->src[1])))
|
nir_src_as_deref(intrin->src[1]),
|
||||||
|
false))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1343,7 +1367,8 @@ initialize_loop_info_state(nir_loop *loop, void *mem_ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_loops(nir_cf_node *cf_node, nir_variable_mode indirect_mask)
|
process_loops(nir_cf_node *cf_node, nir_variable_mode indirect_mask,
|
||||||
|
bool force_unroll_sampler_indirect)
|
||||||
{
|
{
|
||||||
switch (cf_node->type) {
|
switch (cf_node->type) {
|
||||||
case nir_cf_node_block:
|
case nir_cf_node_block:
|
||||||
|
@ -1351,15 +1376,15 @@ process_loops(nir_cf_node *cf_node, nir_variable_mode indirect_mask)
|
||||||
case nir_cf_node_if: {
|
case nir_cf_node_if: {
|
||||||
nir_if *if_stmt = nir_cf_node_as_if(cf_node);
|
nir_if *if_stmt = nir_cf_node_as_if(cf_node);
|
||||||
foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->then_list)
|
foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->then_list)
|
||||||
process_loops(nested_node, indirect_mask);
|
process_loops(nested_node, indirect_mask, force_unroll_sampler_indirect);
|
||||||
foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->else_list)
|
foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->else_list)
|
||||||
process_loops(nested_node, indirect_mask);
|
process_loops(nested_node, indirect_mask, force_unroll_sampler_indirect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case nir_cf_node_loop: {
|
case nir_cf_node_loop: {
|
||||||
nir_loop *loop = nir_cf_node_as_loop(cf_node);
|
nir_loop *loop = nir_cf_node_as_loop(cf_node);
|
||||||
foreach_list_typed(nir_cf_node, nested_node, node, &loop->body)
|
foreach_list_typed(nir_cf_node, nested_node, node, &loop->body)
|
||||||
process_loops(nested_node, indirect_mask);
|
process_loops(nested_node, indirect_mask, force_unroll_sampler_indirect);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1372,6 +1397,7 @@ process_loops(nir_cf_node *cf_node, nir_variable_mode indirect_mask)
|
||||||
|
|
||||||
loop_info_state *state = initialize_loop_info_state(loop, mem_ctx, impl);
|
loop_info_state *state = initialize_loop_info_state(loop, mem_ctx, impl);
|
||||||
state->indirect_mask = indirect_mask;
|
state->indirect_mask = indirect_mask;
|
||||||
|
state->force_unroll_sampler_indirect = force_unroll_sampler_indirect;
|
||||||
|
|
||||||
get_loop_info(state, impl);
|
get_loop_info(state, impl);
|
||||||
|
|
||||||
|
@ -1380,9 +1406,10 @@ process_loops(nir_cf_node *cf_node, nir_variable_mode indirect_mask)
|
||||||
|
|
||||||
void
|
void
|
||||||
nir_loop_analyze_impl(nir_function_impl *impl,
|
nir_loop_analyze_impl(nir_function_impl *impl,
|
||||||
nir_variable_mode indirect_mask)
|
nir_variable_mode indirect_mask,
|
||||||
|
bool force_unroll_sampler_indirect)
|
||||||
{
|
{
|
||||||
nir_index_ssa_defs(impl);
|
nir_index_ssa_defs(impl);
|
||||||
foreach_list_typed(nir_cf_node, node, node, &impl->body)
|
foreach_list_typed(nir_cf_node, node, node, &impl->body)
|
||||||
process_loops(node, indirect_mask);
|
process_loops(node, indirect_mask, force_unroll_sampler_indirect);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,13 @@ nir_metadata_require(nir_function_impl *impl, nir_metadata required, ...)
|
||||||
if (NEEDS_UPDATE(nir_metadata_loop_analysis)) {
|
if (NEEDS_UPDATE(nir_metadata_loop_analysis)) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, required);
|
va_start(ap, required);
|
||||||
nir_loop_analyze_impl(impl, va_arg(ap, nir_variable_mode));
|
/* !! Warning !! Do not move these va_arg() call directly to
|
||||||
|
* nir_loop_analyze_impl() as parameters because the execution order will
|
||||||
|
* become undefined.
|
||||||
|
*/
|
||||||
|
nir_variable_mode mode = va_arg(ap, nir_variable_mode);
|
||||||
|
int force_unroll_sampler_indirect = va_arg(ap, int);
|
||||||
|
nir_loop_analyze_impl(impl, mode, force_unroll_sampler_indirect);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -735,7 +735,8 @@ opt_gcm_impl(nir_shader *shader, nir_function_impl *impl, bool value_number)
|
||||||
nir_metadata_require(impl, nir_metadata_block_index |
|
nir_metadata_require(impl, nir_metadata_block_index |
|
||||||
nir_metadata_dominance);
|
nir_metadata_dominance);
|
||||||
nir_metadata_require(impl, nir_metadata_loop_analysis,
|
nir_metadata_require(impl, nir_metadata_loop_analysis,
|
||||||
shader->options->force_indirect_unrolling);
|
shader->options->force_indirect_unrolling,
|
||||||
|
shader->options->force_indirect_unrolling_sampler);
|
||||||
|
|
||||||
/* A previous pass may have left pass_flags dirty, so clear it all out. */
|
/* A previous pass may have left pass_flags dirty, so clear it all out. */
|
||||||
nir_foreach_block(block, impl)
|
nir_foreach_block(block, impl)
|
||||||
|
|
|
@ -1090,10 +1090,12 @@ exit:
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
nir_opt_loop_unroll_impl(nir_function_impl *impl,
|
nir_opt_loop_unroll_impl(nir_function_impl *impl,
|
||||||
nir_variable_mode indirect_mask)
|
nir_variable_mode indirect_mask,
|
||||||
|
bool force_unroll_sampler_indirect)
|
||||||
{
|
{
|
||||||
bool progress = false;
|
bool progress = false;
|
||||||
nir_metadata_require(impl, nir_metadata_loop_analysis, indirect_mask);
|
nir_metadata_require(impl, nir_metadata_loop_analysis, indirect_mask,
|
||||||
|
(int) force_unroll_sampler_indirect);
|
||||||
nir_metadata_require(impl, nir_metadata_block_index);
|
nir_metadata_require(impl, nir_metadata_block_index);
|
||||||
|
|
||||||
bool has_nested_loop = false;
|
bool has_nested_loop = false;
|
||||||
|
@ -1119,10 +1121,12 @@ nir_opt_loop_unroll(nir_shader *shader)
|
||||||
{
|
{
|
||||||
bool progress = false;
|
bool progress = false;
|
||||||
|
|
||||||
|
bool force_unroll_sampler_indirect = shader->options->force_indirect_unrolling_sampler;
|
||||||
nir_variable_mode indirect_mask = shader->options->force_indirect_unrolling;
|
nir_variable_mode indirect_mask = shader->options->force_indirect_unrolling;
|
||||||
nir_foreach_function(function, shader) {
|
nir_foreach_function(function, shader) {
|
||||||
if (function->impl) {
|
if (function->impl) {
|
||||||
progress |= nir_opt_loop_unroll_impl(function->impl, indirect_mask);
|
progress |= nir_opt_loop_unroll_impl(function->impl, indirect_mask,
|
||||||
|
force_unroll_sampler_indirect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return progress;
|
return progress;
|
||||||
|
|
Loading…
Reference in New Issue