Module: Mesa Branch: main Commit: 9d796b21ac1acce5438c54114f090b9dc709e008 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=9d796b21ac1acce5438c54114f090b9dc709e008
Author: Qiang Yu <[email protected]> Date: Mon Jul 19 09:54:37 2021 +0800 nir/inline_uniforms: add uniforms in condition atomically Unless all uniforms in the condition can be inlined we can lower the if/loop. So we rollback added uniforms when one of uniforms in a if condition fail to be added. Reviewed-by: Marek Olšák <[email protected]> Signed-off-by: Qiang Yu <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11950> --- src/compiler/nir/nir_inline_uniforms.c | 91 ++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/src/compiler/nir/nir_inline_uniforms.c b/src/compiler/nir/nir_inline_uniforms.c index 3e0030bbda2..2099076fa3f 100644 --- a/src/compiler/nir/nir_inline_uniforms.c +++ b/src/compiler/nir/nir_inline_uniforms.c @@ -43,7 +43,8 @@ #define MAX_OFFSET (UINT16_MAX * 4) static bool -src_only_uses_uniforms(const nir_src *src, struct set **uni_offsets) +src_only_uses_uniforms(const nir_src *src, uint32_t *uni_offsets, + unsigned *num_offsets) { if (!src->is_ssa) return false; @@ -56,7 +57,8 @@ src_only_uses_uniforms(const nir_src *src, struct set **uni_offsets) /* TODO: Swizzles are ignored, so vectors can prevent inlining. */ nir_alu_instr *alu = nir_instr_as_alu(instr); for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) { - if (!src_only_uses_uniforms(&alu->src[i].src, uni_offsets)) + if (!src_only_uses_uniforms(&alu->src[i].src, uni_offsets, + num_offsets)) return false; } return true; @@ -76,13 +78,21 @@ src_only_uses_uniforms(const nir_src *src, struct set **uni_offsets) /* UBO loads should be scalarized. */ intr->dest.ssa.num_components == 1 && intr->dest.ssa.bit_size == 32) { - /* Record the uniform offset. */ - if (!*uni_offsets) - *uni_offsets = _mesa_set_create_u32_keys(NULL); + uint32_t offset = nir_src_as_uint(intr->src[1]); + assert(offset < MAX_OFFSET); + + /* Already recorded by other one */ + for (int i = 0; i < *num_offsets; i++) { + if (uni_offsets[i] == offset) + return true; + } + + /* Exceed uniform number limit */ + if (*num_offsets == MAX_INLINABLE_UNIFORMS) + return false; - /* Add 1 because the set doesn't allow NULL keys. */ - _mesa_set_add(*uni_offsets, - (void*)(uintptr_t)(nir_src_as_uint(intr->src[1]) + 1)); + /* Record the uniform offset. */ + uni_offsets[(*num_offsets)++] = offset; return true; } return false; @@ -97,10 +107,41 @@ src_only_uses_uniforms(const nir_src *src, struct set **uni_offsets) } } +static void +add_inlinable_uniforms(const nir_src *cond, uint32_t *uni_offsets, + unsigned *num_offsets) +{ + unsigned new_num = *num_offsets; + + /* Only update uniform number when all uniforms in the expression + * can be inlined. Partially inline uniforms can't lower if/loop. + * + * For example, uniform can be inlined for a shader is limited to 4, + * and we have already added 3 uniforms, then want to deal with + * + * if (uniform0 + uniform1 == 10) + * + * only uniform0 can be inlined due to we exceed the 4 limit. But + * unless both uniform0 and uniform1 are inlined, can we eliminate + * the if statement. + * + * This is even possible when we deal with loop if the induction + * variable init and update also contains uniform like + * + * for (i = uniform0; i < uniform1; i+= uniform2) + * + * unless uniform0, uniform1 and uniform2 can be inlined at once, + * can the loop be unrolled. + */ + if (src_only_uses_uniforms(cond, uni_offsets, &new_num)) + *num_offsets = new_num; +} + void nir_find_inlinable_uniforms(nir_shader *shader) { - struct set *uni_offsets = NULL; + uint32_t uni_offsets[MAX_INLINABLE_UNIFORMS]; + unsigned num_offsets = 0; nir_foreach_function(function, shader) { if (function->impl) { @@ -108,20 +149,7 @@ nir_find_inlinable_uniforms(nir_shader *shader) switch (node->type) { case nir_cf_node_if: { const nir_src *cond = &nir_cf_node_as_if(node)->condition; - struct set *found_offsets = NULL; - - if (src_only_uses_uniforms(cond, &found_offsets) && - found_offsets) { - /* All uniforms are lowerable. Save uniform offsets. */ - set_foreach(found_offsets, entry) { - if (!uni_offsets) - uni_offsets = _mesa_set_create_u32_keys(NULL); - - _mesa_set_add(uni_offsets, entry->key); - } - } - if (found_offsets) - _mesa_set_destroy(found_offsets, NULL); + add_inlinable_uniforms(cond, uni_offsets, &num_offsets); break; } @@ -136,20 +164,9 @@ nir_find_inlinable_uniforms(nir_shader *shader) } } - if (uni_offsets) { - unsigned num = 0; - - set_foreach(uni_offsets, entry) { - /* Subtract 1 because all keys are + 1. */ - uint32_t offset = (uintptr_t)entry->key - 1; - assert(offset < MAX_OFFSET); - - if (num < MAX_INLINABLE_UNIFORMS) - shader->info.inlinable_uniform_dw_offsets[num++] = offset / 4; - } - shader->info.num_inlinable_uniforms = num; - _mesa_set_destroy(uni_offsets, NULL); - } + for (int i = 0; i < num_offsets; i++) + shader->info.inlinable_uniform_dw_offsets[i] = uni_offsets[i] / 4; + shader->info.num_inlinable_uniforms = num_offsets; } void
