From b6d4452661ae77f80d16f5c7f8d55b863ec79ab8 Mon Sep 17 00:00:00 2001 From: Gert Wollny Date: Wed, 15 Apr 2020 16:58:11 +0200 Subject: [PATCH] r600/sfn: Add tesselation shaders Signed-off-by: Gert Wollny Part-of: --- src/gallium/drivers/r600/Makefile.sources | 4 + src/gallium/drivers/r600/meson.build | 4 + src/gallium/drivers/r600/r600_pipe_common.c | 24 ++- src/gallium/drivers/r600/sfn/sfn_nir.cpp | 33 +++- .../drivers/r600/sfn/sfn_shader_tcs.cpp | 121 +++++++++++++ src/gallium/drivers/r600/sfn/sfn_shader_tcs.h | 37 ++++ .../drivers/r600/sfn/sfn_shader_tess_eval.cpp | 159 ++++++++++++++++++ .../drivers/r600/sfn/sfn_shader_tess_eval.h | 41 +++++ 8 files changed, 419 insertions(+), 4 deletions(-) create mode 100644 src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp create mode 100644 src/gallium/drivers/r600/sfn/sfn_shader_tcs.h create mode 100644 src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp create mode 100644 src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h diff --git a/src/gallium/drivers/r600/Makefile.sources b/src/gallium/drivers/r600/Makefile.sources index 7451e72674b..28f2319241a 100644 --- a/src/gallium/drivers/r600/Makefile.sources +++ b/src/gallium/drivers/r600/Makefile.sources @@ -144,6 +144,10 @@ CXX_SOURCES = \ sfn/sfn_shader_fragment.h \ sfn/sfn_shader_geometry.cpp \ sfn/sfn_shader_geometry.h \ + sfn/sfn_shader_tcs.cpp \ + sfn/sfn_shader_tcs.h \ + sfn/sfn_shader_tess_eval.cpp \ + sfn/sfn_shader_tess_eval.h \ sfn/sfn_shader_vertex.cpp \ sfn/sfn_shader_vertex.h \ sfn/sfn_shaderio.cpp \ diff --git a/src/gallium/drivers/r600/meson.build b/src/gallium/drivers/r600/meson.build index 227168a7b24..0bb31dca20a 100644 --- a/src/gallium/drivers/r600/meson.build +++ b/src/gallium/drivers/r600/meson.build @@ -161,6 +161,10 @@ files_r600 = files( 'sfn/sfn_shader_fragment.h', 'sfn/sfn_shader_geometry.cpp', 'sfn/sfn_shader_geometry.h', + 'sfn/sfn_shader_tcs.cpp', + 'sfn/sfn_shader_tcs.h', + 'sfn/sfn_shader_tess_eval.cpp', + 'sfn/sfn_shader_tess_eval.h', 'sfn/sfn_shader_vertex.cpp', 'sfn/sfn_shader_vertex.h', 'sfn/sfn_shaderio.cpp', diff --git a/src/gallium/drivers/r600/r600_pipe_common.c b/src/gallium/drivers/r600/r600_pipe_common.c index b05099975b2..bafe8241e7a 100644 --- a/src/gallium/drivers/r600/r600_pipe_common.c +++ b/src/gallium/drivers/r600/r600_pipe_common.c @@ -1180,6 +1180,24 @@ struct pipe_resource *r600_resource_create_common(struct pipe_screen *screen, } } +const struct nir_shader_compiler_options r600_nir_fs_options = { + .fuse_ffma = true, + .lower_scmp = true, + .lower_flrp32 = true, + .lower_flrp64 = true, + .lower_fpow = true, + .lower_fdiv = true, + .lower_idiv = true, + .lower_fmod = true, + .lower_doubles_options = nir_lower_fp64_full_software, + .lower_int64_options = 0, + .lower_extract_byte = true, + .lower_extract_word = true, + .max_unroll_iterations = 32, + .lower_all_io_to_temps = true, + .vectorize_io = true +}; + const struct nir_shader_compiler_options r600_nir_options = { .fuse_ffma = true, .lower_scmp = true, @@ -1200,13 +1218,17 @@ const struct nir_shader_compiler_options r600_nir_options = { .has_umul24 = true, }; + static const void * r600_get_compiler_options(struct pipe_screen *screen, enum pipe_shader_ir ir, enum pipe_shader_type shader) { assert(ir == PIPE_SHADER_IR_NIR); - return &r600_nir_options; + if (shader == PIPE_SHADER_FRAGMENT) + return &r600_nir_fs_options; + else + return &r600_nir_options; } bool r600_common_screen_init(struct r600_common_screen *rscreen, diff --git a/src/gallium/drivers/r600/sfn/sfn_nir.cpp b/src/gallium/drivers/r600/sfn/sfn_nir.cpp index ce416d92e17..01e5617d0f8 100644 --- a/src/gallium/drivers/r600/sfn/sfn_nir.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_nir.cpp @@ -36,6 +36,8 @@ #include "sfn_shader_fragment.h" #include "sfn_shader_geometry.h" #include "sfn_shader_compute.h" +#include "sfn_shader_tcs.h" +#include "sfn_shader_tess_eval.h" #include "sfn_nir_lower_fs_out_to_vector.h" #include "sfn_ir_to_assembly.h" @@ -62,6 +64,13 @@ bool ShaderFromNir::lower(const nir_shader *shader, r600_pipe_shader *pipe_shade case MESA_SHADER_VERTEX: impl.reset(new VertexShaderFromNir(pipe_shader, *sel, key, gs_shader)); break; + case MESA_SHADER_TESS_CTRL: + sfn_log << SfnLog::trans << "Start TCS\n"; + impl.reset(new TcsShaderFromNir(pipe_shader, *sel, key)); + break; + case MESA_SHADER_TESS_EVAL: + sfn_log << SfnLog::trans << "Start TESS_EVAL\n"; + impl.reset(new TEvalShaderFromNir(pipe_shader, *sel, key, gs_shader)); break; case MESA_SHADER_GEOMETRY: sfn_log << SfnLog::trans << "Start GS\n"; @@ -585,13 +594,31 @@ int r600_shader_from_nir(struct r600_context *rctx, NIR_PASS_V(sel->nir, r600_lower_fs_out_to_vector); if (sel->nir->info.stage == MESA_SHADER_TESS_CTRL || - sel->nir->info.stage == MESA_SHADER_TESS_EVAL) + (sel->nir->info.stage == MESA_SHADER_VERTEX && key->vs.as_ls)) { + NIR_PASS_V(sel->nir, nir_lower_io, nir_var_shader_out, r600_glsl_type_size, + nir_lower_io_lower_64bit_to_32); + NIR_PASS_V(sel->nir, r600_lower_tess_io, (pipe_prim_type)key->tcs.prim_mode); + } + + if (sel->nir->info.stage == MESA_SHADER_TESS_CTRL || + sel->nir->info.stage == MESA_SHADER_TESS_EVAL) { NIR_PASS_V(sel->nir, nir_lower_io, nir_var_shader_in, r600_glsl_type_size, nir_lower_io_lower_64bit_to_32); + } + + if (sel->nir->info.stage == MESA_SHADER_TESS_CTRL || + sel->nir->info.stage == MESA_SHADER_TESS_EVAL || + (sel->nir->info.stage == MESA_SHADER_VERTEX && key->vs.as_ls)) { + auto prim_type = sel->nir->info.stage == MESA_SHADER_TESS_CTRL ? + key->tcs.prim_mode : sel->nir->info.tess.primitive_mode; + NIR_PASS_V(sel->nir, r600_lower_tess_io, static_cast(prim_type)); + } + if (sel->nir->info.stage == MESA_SHADER_TESS_CTRL) - NIR_PASS_V(sel->nir, nir_lower_io, nir_var_shader_out, r600_glsl_type_size, - nir_lower_io_lower_64bit_to_32); + NIR_PASS_V(sel->nir, r600_append_tcs_TF_emission, + (pipe_prim_type)key->tcs.prim_mode); + const nir_function *func = reinterpret_cast(exec_list_get_head_const(&sel->nir->functions)); bool optimize = func->impl->registers.length() == 0 && !has_saturate(func); diff --git a/src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp b/src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp new file mode 100644 index 00000000000..11e657e67a3 --- /dev/null +++ b/src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp @@ -0,0 +1,121 @@ +#include "sfn_shader_tcs.h" +#include "sfn_instruction_gds.h" +#include "tgsi/tgsi_from_mesa.h" + +namespace r600 { + +TcsShaderFromNir::TcsShaderFromNir(r600_pipe_shader *sh, + r600_pipe_shader_selector& sel, + const r600_shader_key& key): + ShaderFromNirProcessor (PIPE_SHADER_TESS_CTRL, sel, sh->shader, + sh->scratch_space_needed), + m_reserved_registers(0) +{ + sh_info().tcs_prim_mode = key.tcs.prim_mode; +} + +bool TcsShaderFromNir::scan_sysvalue_access(nir_instr *instr) +{ + if (instr->type != nir_instr_type_intrinsic) + return true; + + auto intr = nir_instr_as_intrinsic(instr); + + switch (intr->intrinsic) { + case nir_intrinsic_load_primitive_id: + m_sv_values.set(es_primitive_id); + break; + case nir_intrinsic_load_invocation_id: + m_sv_values.set(es_invocation_id); + break; + case nir_intrinsic_load_tcs_rel_patch_id_r600: + m_sv_values.set(es_rel_patch_id); + break; + case nir_intrinsic_load_tcs_tess_factor_base_r600: + m_sv_values.set(es_tess_factor_base); + break; + default: + + ; + } + return true; +} + +bool TcsShaderFromNir::do_process_outputs(nir_variable *output) +{ + unsigned name, sid; + + tgsi_get_gl_varying_semantic(static_cast(output->data.location), + true, &name, &sid); + + auto& io = sh_info().output[sh_info().noutput++]; + io.name = name; + io.write_mask = ((1 << output->type->components()) - 1) + << output->data.location_frac; + return true; +} + +bool TcsShaderFromNir::allocate_reserved_registers() +{ + if (m_sv_values.test(es_primitive_id)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,0); + gpr->set_as_input(); + m_primitive_id.reset(gpr); + } + + if (m_sv_values.test(es_invocation_id)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,2); + gpr->set_as_input(); + m_invocation_id.reset(gpr); + } + + if (m_sv_values.test(es_rel_patch_id)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,1); + gpr->set_as_input(); + m_rel_patch_id.reset(gpr); + } + + if (m_sv_values.test(es_tess_factor_base)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,3); + gpr->set_as_input(); + m_tess_factor_base.reset(gpr); + } + + set_reserved_registers(m_reserved_registers); + + return true; +} + +bool TcsShaderFromNir::emit_intrinsic_instruction_override(nir_intrinsic_instr* instr) +{ + switch (instr->intrinsic) { + case nir_intrinsic_load_tcs_rel_patch_id_r600: + return load_preloaded_value(instr->dest, 0, m_rel_patch_id); + case nir_intrinsic_load_invocation_id: + return load_preloaded_value(instr->dest, 0, m_invocation_id); + case nir_intrinsic_load_primitive_id: + return load_preloaded_value(instr->dest, 0, m_primitive_id); + case nir_intrinsic_load_tcs_tess_factor_base_r600: + return load_preloaded_value(instr->dest, 0, m_tess_factor_base); + case nir_intrinsic_store_tf_r600: + return store_tess_factor(instr); + default: + return false; + } +} + +bool TcsShaderFromNir::store_tess_factor(nir_intrinsic_instr* instr) +{ + const GPRVector::Swizzle& swizzle = (instr->src[0].ssa->num_components == 4) ? + GPRVector::Swizzle({0, 1, 2, 3}) : GPRVector::Swizzle({0, 1, 7, 7}); + std::unique_ptr val(vec_from_nir_with_fetch_constant(instr->src[0], + 0xf, swizzle)); + emit_instruction(new GDSStoreTessFactor(*val)); + return true; +} + +} diff --git a/src/gallium/drivers/r600/sfn/sfn_shader_tcs.h b/src/gallium/drivers/r600/sfn/sfn_shader_tcs.h new file mode 100644 index 00000000000..8e6d4f1b15f --- /dev/null +++ b/src/gallium/drivers/r600/sfn/sfn_shader_tcs.h @@ -0,0 +1,37 @@ +#ifndef TCSSHADERFROMNIR_H +#define TCSSHADERFROMNIR_H + +#include "sfn_shader_base.h" + +namespace r600 { + +class TcsShaderFromNir : public ShaderFromNirProcessor +{ +public: + TcsShaderFromNir(r600_pipe_shader *sh, r600_pipe_shader_selector& sel, const r600_shader_key& key); + bool scan_sysvalue_access(nir_instr *instr) override; + +private: + bool allocate_reserved_registers() override; + bool emit_intrinsic_instruction_override(nir_intrinsic_instr* instr) override; + bool store_tess_factor(nir_intrinsic_instr* instr); + + bool do_process_inputs(nir_variable *input) override { return true;} + bool do_process_outputs(nir_variable *output) override; + bool do_emit_load_deref(const nir_variable *in_var, nir_intrinsic_instr* instr) override { return true;} + bool do_emit_store_deref(const nir_variable *out_var, nir_intrinsic_instr* instr) override { return true;} + void do_finalize() override {} + + int m_reserved_registers; + PValue m_patch_id; + PValue m_rel_patch_id; + PValue m_invocation_id; + PValue m_primitive_id; + PValue m_tess_factor_base; + + +}; + +} + +#endif // TCSSHADERFROMNIR_H diff --git a/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp b/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp new file mode 100644 index 00000000000..0c114194bf6 --- /dev/null +++ b/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp @@ -0,0 +1,159 @@ +#include "sfn_shader_tess_eval.h" +#include "tgsi/tgsi_from_mesa.h" + +namespace r600 { + +TEvalShaderFromNir::TEvalShaderFromNir(r600_pipe_shader *sh, r600_pipe_shader_selector& sel, + const r600_shader_key& key, r600_shader *gs_shader): + VertexStage(PIPE_SHADER_TESS_EVAL, sel, sh->shader, + sh->scratch_space_needed), + m_reserved_registers(0), + m_key(key) + +{ + sh->shader.tes_as_es = key.tes.as_es; + if (key.tes.as_es) + m_export_processor.reset(new VertexStageExportForGS(*this, gs_shader)); + else + m_export_processor.reset(new VertexStageExportForFS(*this, &sel.so, sh, key)); +} + +bool TEvalShaderFromNir::do_process_inputs(nir_variable *input) +{ + if (input->data.location == VARYING_SLOT_POS || + input->data.location == VARYING_SLOT_PSIZ || + input->data.location == VARYING_SLOT_CLIP_DIST0 || + input->data.location == VARYING_SLOT_CLIP_DIST1 || + (input->data.location >= VARYING_SLOT_VAR0 && + input->data.location <= VARYING_SLOT_VAR31) || + (input->data.location >= VARYING_SLOT_TEX0 && + input->data.location <= VARYING_SLOT_TEX7) || + (input->data.location >= VARYING_SLOT_PATCH0 && + input->data.location <= VARYING_SLOT_TESS_MAX)) { + + r600_shader_io& io = sh_info().input[input->data.driver_location]; + tgsi_get_gl_varying_semantic(static_cast( input->data.location), + true, &io.name, &io.sid); + ++sh_info().ninput; + return true; + } + + return false; + +} + +bool TEvalShaderFromNir::scan_sysvalue_access(nir_instr *instr) +{ + if (instr->type != nir_instr_type_intrinsic) + return true; + + auto ir = nir_instr_as_intrinsic(instr); + + switch (ir->intrinsic) { + case nir_intrinsic_load_tess_coord: + m_sv_values.set(es_tess_coord); + break; + case nir_intrinsic_load_primitive_id: + m_sv_values.set(es_primitive_id); + break; + case nir_intrinsic_load_tcs_rel_patch_id_r600: + m_sv_values.set(es_rel_patch_id); + break; + default: + ; + } + return true; +} + +bool TEvalShaderFromNir::allocate_reserved_registers() +{ + if (m_sv_values.test(es_tess_coord)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,0); + gpr->set_as_input(); + m_tess_coord[0].reset(gpr); + gpr = new GPRValue(0,1); + gpr->set_as_input(); + m_tess_coord[1].reset(gpr); + } + + if (m_sv_values.test(es_rel_patch_id)) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,2); + gpr->set_as_input(); + m_rel_patch_id.reset(gpr); + } + + if (m_sv_values.test(es_primitive_id) || + m_key.vs.as_gs_a) { + m_reserved_registers = 1; + auto gpr = new GPRValue(0,3); + gpr->set_as_input(); + m_primitive_id.reset(gpr); + if (m_key.vs.as_gs_a) + inject_register(0, 3, m_primitive_id, false); + } + set_reserved_registers(m_reserved_registers); + return true; +} + +bool TEvalShaderFromNir::load_tess_z_coord(nir_intrinsic_instr* instr) +{ + if (m_tess_coord[2]) + return load_preloaded_value(instr->dest, 2, m_tess_coord[2]); + + m_tess_coord[2] = from_nir(instr->dest, 2); + emit_instruction(new AluInstruction(op2_add, m_tess_coord[2], Value::one_f, m_tess_coord[0], {alu_last_instr, alu_write, alu_src1_neg})); + emit_instruction(new AluInstruction(op2_add, m_tess_coord[2], m_tess_coord[2], m_tess_coord[1], {alu_last_instr, alu_write, alu_src1_neg})); + return true; +} + +bool TEvalShaderFromNir::emit_intrinsic_instruction_override(nir_intrinsic_instr* instr) +{ + switch (instr->intrinsic) { + case nir_intrinsic_load_tess_coord: + return load_preloaded_value(instr->dest, 0, m_tess_coord[0]) && + load_preloaded_value(instr->dest, 1, m_tess_coord[1]) && + load_tess_z_coord(instr); + case nir_intrinsic_load_primitive_id: + return load_preloaded_value(instr->dest, 0, m_primitive_id); + case nir_intrinsic_load_tcs_rel_patch_id_r600: + return load_preloaded_value(instr->dest, 0, m_rel_patch_id); + default: + return false; + } +} + + +bool TEvalShaderFromNir::do_process_outputs(nir_variable *output) +{ + return m_export_processor->do_process_outputs(output); +} + +bool TEvalShaderFromNir::do_emit_store_deref(const nir_variable *out_var, nir_intrinsic_instr* instr) +{ + return m_export_processor->store_deref(out_var, instr); +} + +void TEvalShaderFromNir::do_finalize() +{ + m_export_processor->finalize_exports(); +} + + +bool TEvalShaderFromNir::emit_load_tess_coord(nir_intrinsic_instr* instr) +{ + bool result = load_preloaded_value(instr->dest, 0, m_tess_coord[0]) && + load_preloaded_value(instr->dest, 1, m_tess_coord[1]); + + m_tess_coord[2] = from_nir(instr->dest, 2); + + + emit_instruction(new AluInstruction(op2_add, m_tess_coord[2], m_tess_coord[2], + m_tess_coord[0], {alu_last_instr, alu_write, alu_src0_neg})); + emit_instruction(new AluInstruction(op2_add, m_tess_coord[2], m_tess_coord[2], + m_tess_coord[1], {alu_last_instr, alu_write, alu_src0_neg})); + return result; +} + +} diff --git a/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h b/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h new file mode 100644 index 00000000000..ce715e2d727 --- /dev/null +++ b/src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h @@ -0,0 +1,41 @@ +#ifndef TEVALSHADERFROMNIR_H +#define TEVALSHADERFROMNIR_H + +#include "sfn_shader_base.h" +#include "sfn_vertexstageexport.h" + +namespace r600 { + +class TEvalShaderFromNir : public VertexStage +{ +public: + TEvalShaderFromNir(r600_pipe_shader *sh, r600_pipe_shader_selector& sel, + const r600_shader_key& key, r600_shader *gs_shader); + bool scan_sysvalue_access(nir_instr *instr) override; + PValue primitive_id() override {return m_primitive_id;} + private: + bool allocate_reserved_registers() override; + bool emit_intrinsic_instruction_override(nir_intrinsic_instr* instr) override; + bool emit_load_tess_coord(nir_intrinsic_instr* instr); + bool load_tess_z_coord(nir_intrinsic_instr* instr); + + bool do_process_inputs(nir_variable *input) override; + bool do_process_outputs(nir_variable *output) override; + bool do_emit_load_deref(const nir_variable *in_var, nir_intrinsic_instr* instr) override { return true;} + bool do_emit_store_deref(const nir_variable *out_var, nir_intrinsic_instr* instr) override; + void do_finalize() override; + + + unsigned m_reserved_registers; + PValue m_tess_coord[3]; + PValue m_rel_patch_id; + PValue m_primitive_id; + + std::unique_ptr m_export_processor; + const r600_shader_key& m_key; +}; + + +} + +#endif // TEVALSHADERFROMNIR_H -- 2.30.2