Commit b6d44526 authored by Gert Wollny's avatar Gert Wollny Committed by Marge Bot

r600/sfn: Add tesselation shaders

Signed-off-by: Gert Wollny's avatarGert Wollny <gert.wollny@collabora.com>
Part-of: <mesa/mesa!4714>
parent d77b81ce
......@@ -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 \
......
......@@ -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',
......
......@@ -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,
......
......@@ -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);
......
#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;
}
}
#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
#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;
}
}
#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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment