From 826d3afb8f421a62020308813397e541e672381e Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Fri, 30 Jan 2015 01:16:49 -0800 Subject: [PATCH] i965/fs: Add ARB_fragment_program support to the NIR backend. Use prog_to_nir where we would normally call glsl_to_nir, handle program parameter lists, and skip a few things that don't exist. Using NIR generates much better shader code than Mesa IR, since we get real optimizations, as opposed to prog_optimize: total instructions in shared programs: 314007 -> 279892 (-10.86%) instructions in affected programs: 285173 -> 251058 (-11.96%) helped: 2001 HURT: 67 GAINED: 4 LOST: 7 v2: Change early return in nir_setup_uniforms to if/else (Jordan). Signed-off-by: Kenneth Graunke Reviewed-by: Jordan Justen Reviewed-by: Connor Abbott --- src/mesa/drivers/dri/i965/brw_fs.cpp | 16 ++++----- src/mesa/drivers/dri/i965/brw_fs_nir.cpp | 61 +++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index a57f501..6969286 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -3954,15 +3954,13 @@ fs_visitor::run_fs() /* Generate FS IR for main(). (the visitor only descends into * functions called "main"). */ - if (shader) { - if (env_var_as_boolean("INTEL_USE_NIR", false)) { - emit_nir_code(); - } else { - foreach_in_list(ir_instruction, ir, shader->base.ir) { - base_ir = ir; - this->result = reg_undef; - ir->accept(this); - } + if (env_var_as_boolean("INTEL_USE_NIR", false)) { + emit_nir_code(); + } else if (shader) { + foreach_in_list(ir_instruction, ir, shader->base.ir) { + base_ir = ir; + this->result = reg_undef; + ir->accept(this); } } else { emit_fragment_program_code(); diff --git a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp index 0b8ed1a..21e52fe 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp @@ -24,6 +24,7 @@ #include "glsl/ir.h" #include "glsl/ir_optimization.h" #include "glsl/nir/glsl_to_nir.h" +#include "program/prog_to_nir.h" #include "brw_fs.h" #include "brw_nir.h" @@ -86,9 +87,15 @@ fs_visitor::emit_nir_code() const nir_shader_compiler_options *options = ctx->Const.ShaderCompilerOptions[stage].NirOptions; - /* first, lower the GLSL IR shader to NIR */ - lower_output_reads(shader->base.ir); - nir_shader *nir = glsl_to_nir(&shader->base, options); + nir_shader *nir; + /* First, lower the GLSL IR or Mesa IR to NIR */ + if (shader_prog) { + lower_output_reads(shader->base.ir); + nir = glsl_to_nir(&shader->base, options); + } else { + nir = prog_to_nir(prog, options); + nir_convert_to_ssa(nir); /* turn registers into SSA */ + } nir_validate_shader(nir); nir_lower_global_vars_to_local(nir); @@ -106,9 +113,18 @@ fs_visitor::emit_nir_code() /* Get rid of split copies */ nir_optimize(nir); - nir_assign_var_locations_scalar_direct_first(nir, &nir->uniforms, - &num_direct_uniforms, - &nir->num_uniforms); + if (shader_prog) { + nir_assign_var_locations_scalar_direct_first(nir, &nir->uniforms, + &num_direct_uniforms, + &nir->num_uniforms); + } else { + /* ARB programs generally create a giant array of "uniform" data, and allow + * indirect addressing without any boundaries. In the absence of bounds + * analysis, it's all or nothing. num_direct_uniforms is only useful when + * we have some direct and some indirect access; it doesn't matter here. + */ + num_direct_uniforms = 0; + } nir_assign_var_locations_scalar(&nir->inputs, &nir->num_inputs); nir_assign_var_locations_scalar(&nir->outputs, &nir->num_outputs); @@ -118,8 +134,10 @@ fs_visitor::emit_nir_code() nir_remove_dead_variables(nir); nir_validate_shader(nir); - nir_lower_samplers(nir, shader_prog, shader->base.Program); - nir_validate_shader(nir); + if (shader_prog) { + nir_lower_samplers(nir, shader_prog, shader->base.Program); + nir_validate_shader(nir); + } nir_lower_system_values(nir); nir_validate_shader(nir); @@ -320,16 +338,25 @@ fs_visitor::nir_setup_uniforms(nir_shader *shader) if (dispatch_width != 8) return; - foreach_list_typed(nir_variable, var, node, &shader->uniforms) { - /* UBO's and atomics don't take up space in the uniform file */ - - if (var->interface_type != NULL || var->type->contains_atomic()) - continue; + if (shader_prog) { + foreach_list_typed(nir_variable, var, node, &shader->uniforms) { + /* UBO's and atomics don't take up space in the uniform file */ + if (var->interface_type != NULL || var->type->contains_atomic()) + continue; - if (strncmp(var->name, "gl_", 3) == 0) - nir_setup_builtin_uniform(var); - else - nir_setup_uniform(var); + if (strncmp(var->name, "gl_", 3) == 0) + nir_setup_builtin_uniform(var); + else + nir_setup_uniform(var); + } + } else { + /* prog_to_nir doesn't create uniform variables; set param up directly. */ + for (unsigned p = 0; p < prog->Parameters->NumParameters; p++) { + for (unsigned int i = 0; i < 4; i++) { + stage_prog_data->param[4 * p + i] = + &prog->Parameters->ParameterValues[p][i]; + } + } } } -- 2.7.4