diff --git a/src/gallium/drivers/r300/compiler/nir_to_rc.c b/src/gallium/drivers/r300/compiler/nir_to_rc.c index bfc65970429..d909389f03e 100644 --- a/src/gallium/drivers/r300/compiler/nir_to_rc.c +++ b/src/gallium/drivers/r300/compiler/nir_to_rc.c @@ -2465,6 +2465,8 @@ const void *nir_to_rc_options(struct nir_shader *s, else NIR_PASS_V(s, r300_nir_lower_fcsel_r300); NIR_PASS_V(s, r300_nir_lower_flrp); + } else { + NIR_PASS_V(s, r300_nir_lower_comparison_fs); } NIR_PASS_V(s, r300_nir_opt_algebraic_late); NIR_PASS_V(s, nir_opt_dce); diff --git a/src/gallium/drivers/r300/compiler/r300_nir.c b/src/gallium/drivers/r300/compiler/r300_nir.c index 3cb2faf2098..b137dc02742 100644 --- a/src/gallium/drivers/r300/compiler/r300_nir.c +++ b/src/gallium/drivers/r300/compiler/r300_nir.c @@ -137,6 +137,9 @@ r300_optimize_nir(struct nir_shader *s, struct pipe_screen *screen) nir_metadata_block_index | nir_metadata_dominance, NULL); NIR_PASS(progress, s, nir_opt_peephole_select, is_r500 ? 8 : ~0, true, true); + if (s->info.stage == MESA_SHADER_FRAGMENT) { + NIR_PASS(progress, s, r300_nir_lower_bool_to_float_fs); + } NIR_PASS(progress, s, nir_opt_algebraic); NIR_PASS(progress, s, nir_opt_constant_folding); nir_load_store_vectorize_options vectorize_opts = { diff --git a/src/gallium/drivers/r300/compiler/r300_nir.h b/src/gallium/drivers/r300/compiler/r300_nir.h index 2a49864af96..2739b4539d5 100644 --- a/src/gallium/drivers/r300/compiler/r300_nir.h +++ b/src/gallium/drivers/r300/compiler/r300_nir.h @@ -47,6 +47,19 @@ is_ubo_or_input(UNUSED struct hash_table *ht, const nir_alu_instr *instr, } } +static inline bool +is_not_used_in_single_if(const nir_alu_instr *instr) +{ + unsigned if_uses = 0; + nir_foreach_use(src, &instr->def) { + if (nir_src_is_if(src)) + if_uses++; + else + return true; + } + return if_uses != 1; +} + static inline bool is_only_used_by_load_ubo_vec4(const nir_alu_instr *instr) { @@ -77,6 +90,8 @@ extern bool r300_nir_fuse_fround_d3d9(struct nir_shader *shader); extern bool r300_nir_lower_bool_to_float(struct nir_shader *shader); +extern bool r300_nir_lower_bool_to_float_fs(struct nir_shader *shader); + extern bool r300_nir_prepare_presubtract(struct nir_shader *shader); extern bool r300_nir_opt_algebraic_late(struct nir_shader *shader); @@ -89,4 +104,6 @@ extern bool r300_nir_lower_fcsel_r300(nir_shader *shader); extern bool r300_nir_lower_flrp(nir_shader *shader); +extern bool r300_nir_lower_comparison_fs(nir_shader *shader); + #endif /* R300_NIR_H */ diff --git a/src/gallium/drivers/r300/compiler/r300_nir_algebraic.py b/src/gallium/drivers/r300/compiler/r300_nir_algebraic.py index fc6a8519429..f77b3b49d4a 100644 --- a/src/gallium/drivers/r300/compiler/r300_nir_algebraic.py +++ b/src/gallium/drivers/r300/compiler/r300_nir_algebraic.py @@ -93,6 +93,9 @@ r300_nir_opt_algebraic_late = [ # does not and blows up. Clean this up. (('fneg', ('fneg', a)), a), (('fabs', ('fneg', a)), ('fabs', a)), + # Some cleanups after comparison lowering if one of the operands is 0. + (('fadd', a, 0.0), a), + (('fadd', a, ('fneg', 0.0)), a) ] # This is very late flrp lowering to clean up after bcsel->fcsel->flrp. @@ -105,6 +108,20 @@ r300_nir_lower_fcsel_r300 = [ (('fcsel_ge', a, b, c), ('flrp', c, b, ('sge', a, 0.0))) ] +# Fragment shaders have no comparison opcodes. However, we can encode the comparison +# in the aluresults operation, which is than used by next if. So if the comparison result +# is used only in a single if, we can handle it just fine on R500. +r300_nir_lower_comparison_fs = [ + (('seq(is_not_used_in_single_if)', 'a@32', 'b@32'), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), 1.0, 0.0)), + (('sne(is_not_used_in_single_if)', 'a@32', 'b@32'), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), 0.0, 1.0)), + (('slt(is_not_used_in_single_if)', 'a@32', 'b@32'), + ('fcsel_ge', ('fadd', a, ('fneg', b)), 0.0, 1.0)), + (('sge(is_not_used_in_single_if)', 'a@32', 'b@32'), + ('fcsel_ge', ('fadd', a, ('fneg', b)), 1.0, 0.0)), +] + r300_nir_post_integer_lowering = [ # If ffloor result is used only for indirect constant load, we can get rid of it # completelly as ntt emits ARL by default which already does the flooring. @@ -148,7 +165,26 @@ def main(): ('fcsel', ('slt', a, b), c, d), "options->has_fused_comp_and_csel"), (('bcsel@32(is_only_used_as_float)', ('fge', 'a@32', 'b@32'), c, d), ('fcsel', ('sge', a, b), c, d), "options->has_fused_comp_and_csel"), -] + ] + + r300_nir_lower_bool_to_float_fs = [ + (('bcsel@32(r300_is_only_used_as_float)', ignore_exact('feq', 'a@32', 'b@32'), c, d), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), c, d)), + (('bcsel@32(r300_is_only_used_as_float)', ignore_exact('fneu', 'a@32', 'b@32'), c, d), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), d, c)), + (('bcsel@32(r300_is_only_used_as_float)', ignore_exact('flt', 'a@32', 'b@32'), c, d), + ('fcsel_ge', ('fadd', a, ('fneg', b)), d, c)), + (('bcsel@32(r300_is_only_used_as_float)', ignore_exact('fge', 'a@32', 'b@32'), c, d), + ('fcsel_ge', ('fadd', a, ('fneg', b)), c, d)), + (('b2f32', ('feq', 'a@32', 'b@32')), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), 1.0, 0.0)), + (('b2f32', ('fneu', 'a@32', 'b@32')), + ('fcsel_ge', ('fneg', ('fabs', ('fadd', a, ('fneg', b)))), 0.0, 1.0)), + (('b2f32', ('flt', 'a@32', 'b@32')), + ('fcsel_ge', ('fadd', a, ('fneg', b)), 0.0, 1.0)), + (('b2f32', ('fge', 'a@32', 'b@32')), + ('fcsel_ge', ('fadd', a, ('fneg', b)), 1.0, 0.0)), + ] with open(args.output, 'w') as f: f.write('#include "compiler/r300_nir.h"') @@ -165,6 +201,9 @@ def main(): f.write(nir_algebraic.AlgebraicPass("r300_nir_lower_bool_to_float", r300_nir_lower_bool_to_float).render()) + f.write(nir_algebraic.AlgebraicPass("r300_nir_lower_bool_to_float_fs", + r300_nir_lower_bool_to_float_fs).render()) + f.write(nir_algebraic.AlgebraicPass("r300_nir_prepare_presubtract", r300_nir_prepare_presubtract).render()) @@ -180,5 +219,8 @@ def main(): f.write(nir_algebraic.AlgebraicPass("r300_nir_lower_fcsel_r300", r300_nir_lower_fcsel_r300).render()) + f.write(nir_algebraic.AlgebraicPass("r300_nir_lower_comparison_fs", + r300_nir_lower_comparison_fs).render()) + if __name__ == '__main__': main()