aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/r600
diff options
context:
space:
mode:
authorGert Wollny <[email protected]>2020-04-15 16:58:11 +0200
committerMarge Bot <[email protected]>2020-04-28 08:06:33 +0000
commitb6d4452661ae77f80d16f5c7f8d55b863ec79ab8 (patch)
tree18f8e157fc9056e1e89dfb4ebc4446409b19822a /src/gallium/drivers/r600
parentd77b81ce50ea05736bc0554a1062156caffed358 (diff)
r600/sfn: Add tesselation shaders
Signed-off-by: Gert Wollny <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4714>
Diffstat (limited to 'src/gallium/drivers/r600')
-rw-r--r--src/gallium/drivers/r600/Makefile.sources4
-rw-r--r--src/gallium/drivers/r600/meson.build4
-rw-r--r--src/gallium/drivers/r600/r600_pipe_common.c24
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_nir.cpp33
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_shader_tcs.cpp121
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_shader_tcs.h37
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.cpp159
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_shader_tess_eval.h41
8 files changed, 419 insertions, 4 deletions
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<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
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<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
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<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
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<VertexStageExportBase> m_export_processor;
+ const r600_shader_key& m_key;
+};
+
+
+}
+
+#endif // TEVALSHADERFROMNIR_H