r600/sfn: Add tesselation shaders
authorGert Wollny <gert.wollny@collabora.com>
Wed, 15 Apr 2020 14:58:11 +0000 (16:58 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 28 Apr 2020 08:06:33 +0000 (08:06 +0000)
Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4714>

src/gallium/drivers/r600/Makefile.sources
src/gallium/drivers/r600/meson.build
src/gallium/drivers/r600/r600_pipe_common.c
src/gallium/drivers/r600/sfn/sfn_nir.cpp
src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp [new file with mode: 0644]
src/gallium/drivers/r600/sfn/sfn_shader_tcs.h [new file with mode: 0644]
src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp [new file with mode: 0644]
src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h [new file with mode: 0644]

index 7451e72674b10f34c1b178cf68106f6ae12fb06a..28f2319241ac572401346ab6ff379cb986bfb3c7 100644 (file)
@@ -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 \
index 227168a7b24e3d129636303d6319c5b0e17f67af..0bb31dca20ad60c3e44116039f6653d8dd1918d1 100644 (file)
@@ -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',
index b05099975b2e21870ae7800d062e28aec6ac546b..bafe8241e7a715fac6bbfec9a1657eb4802bfb29 100644 (file)
@@ -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,
index ce416d92e17dc4f7e637372de6a749b959c769d6..01e5617d0f8319f2cb4a767b0b5be6ad09560694 100644 (file)
@@ -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<pipe_prim_type>(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<const nir_function *>(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 (file)
index 0000000..11e657e
--- /dev/null
@@ -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<gl_varying_slot>(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<GPRVector> 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 (file)
index 0000000..8e6d4f1
--- /dev/null
@@ -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 (file)
index 0000000..0c11419
--- /dev/null
@@ -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<gl_varying_slot>( 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 (file)
index 0000000..ce715e2
--- /dev/null
@@ -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<VertexStageExportBase> m_export_processor;
+        const r600_shader_key& m_key;
+};
+
+
+}
+
+#endif // TEVALSHADERFROMNIR_H