/* -*- mesa-c++ -*- * * Copyright (c) 2022 Collabora LTD * * Author: Gert Wollny * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "sfn_instr_export.h" #include "sfn_shader_tess.h" #include "sfn_shader_vs.h" #include namespace r600 { using std::string; TCSShader::TCSShader(const r600_shader_key& key): Shader("TCS"), m_tcs_prim_mode(key.tcs.prim_mode) { } bool TCSShader::do_scan_instruction(nir_instr *instr) { if (instr->type != nir_instr_type_intrinsic) return false; nir_intrinsic_instr *ii = nir_instr_as_intrinsic(instr); switch (ii->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 false; ; } return true; } int TCSShader::do_allocate_reserved_registers() { if (m_sv_values.test(es_primitive_id)) { m_primitive_id = value_factory().allocate_pinned_register(0, 0); m_primitive_id->pin_live_range(true); } if (m_sv_values.test(es_invocation_id)) { m_invocation_id = value_factory().allocate_pinned_register(0, 2); m_invocation_id->pin_live_range(true); } if (m_sv_values.test(es_rel_patch_id)) { m_rel_patch_id = value_factory().allocate_pinned_register(0, 1);; m_rel_patch_id->pin_live_range(true); } if (m_sv_values.test(es_tess_factor_base)) { m_tess_factor_base = value_factory().allocate_pinned_register(0, 3); m_tess_factor_base->pin_live_range(true); } return value_factory().next_register_index();; } bool TCSShader::process_stage_intrinsic(nir_intrinsic_instr *instr) { switch (instr->intrinsic) { case nir_intrinsic_load_tcs_rel_patch_id_r600: return emit_simple_mov(instr->dest, 0, m_rel_patch_id); case nir_intrinsic_load_invocation_id: return emit_simple_mov(instr->dest, 0, m_invocation_id); case nir_intrinsic_load_primitive_id: return emit_simple_mov(instr->dest, 0, m_primitive_id); case nir_intrinsic_load_tcs_tess_factor_base_r600: return emit_simple_mov(instr->dest, 0, m_tess_factor_base); case nir_intrinsic_store_tf_r600: return store_tess_factor(instr); default: return false; } } bool TCSShader::store_tess_factor(nir_intrinsic_instr* instr) { bool two_parts = nir_src_num_components(instr->src[0]) == 4; auto value0 = value_factory().temp_vec4(pin_group, {0, 1, 7, 7}); emit_instruction(new AluInstr(op1_mov, value0[0], value_factory().src(instr->src[0], 0), AluInstr::write)); emit_instruction(new AluInstr(op1_mov, value0[1], value_factory().src(instr->src[0], 1), two_parts ? AluInstr::write : AluInstr::last_write)); if (two_parts) { auto value1 = value_factory().temp_vec4(pin_group, {2, 3, 7, 7}); emit_instruction(new AluInstr(op1_mov, value1[0], value_factory().src(instr->src[0], 2), AluInstr::write)); emit_instruction(new AluInstr(op1_mov, value1[1], value_factory().src(instr->src[0], 3), AluInstr::last_write)); emit_instruction(new WriteTFInstr(value1)); } emit_instruction(new WriteTFInstr(value0)); return true; } void TCSShader::do_get_shader_info(r600_shader *sh_info) { sh_info->processor_type = PIPE_SHADER_TESS_CTRL; sh_info->tcs_prim_mode = m_tcs_prim_mode; } bool TCSShader::read_prop(std::istream& is) { string value; is >> value; auto splitpos = value.find(':'); assert(splitpos != string::npos); std::istringstream ival(value); string name; string val; std::getline(ival, name, ':'); if (name == "TCS_PRIM_MODE") ival >> m_tcs_prim_mode; else return false; return true; } void TCSShader::do_print_properties(std::ostream& os) const { os << "PROP TCS_PRIM_MODE:" << m_tcs_prim_mode << "\n"; } TESShader::TESShader(const pipe_stream_output_info *so_info, const r600_shader *gs_shader, const r600_shader_key& key): VertexStageShader("TES"), m_vs_as_gs_a(key.vs.as_gs_a), m_tes_as_es(key.tes.as_es) { if (key.tes.as_es) m_export_processor = new VertexExportForGS(this, gs_shader); else m_export_processor = new VertexExportForFs(this, so_info, key); } bool TESShader::do_scan_instruction(nir_instr *instr) { if (instr->type != nir_instr_type_intrinsic) return false; auto intr = nir_instr_as_intrinsic(instr); switch (intr->intrinsic) { case nir_intrinsic_load_tess_coord_r600: 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; case nir_intrinsic_store_output: { int driver_location = nir_intrinsic_base(intr); int location = nir_intrinsic_io_semantics(intr).location; auto semantic = r600_get_varying_semantic(location); tgsi_semantic name = (tgsi_semantic)semantic.first; unsigned sid = semantic.second; auto write_mask = nir_intrinsic_write_mask(intr); if (location == VARYING_SLOT_LAYER) write_mask = 4; ShaderOutput output(driver_location, name, write_mask); output.set_sid(sid); switch (location) { case VARYING_SLOT_PSIZ: case VARYING_SLOT_POS: case VARYING_SLOT_CLIP_VERTEX: case VARYING_SLOT_EDGE: { break; } case VARYING_SLOT_CLIP_DIST0: case VARYING_SLOT_CLIP_DIST1: case VARYING_SLOT_VIEWPORT: case VARYING_SLOT_LAYER: case VARYING_SLOT_VIEW_INDEX: default: output.set_is_param(true); } add_output(output); break; } default: return false; } return true; } int TESShader::do_allocate_reserved_registers() { if (m_sv_values.test(es_tess_coord)) { m_tess_coord[0] = value_factory().allocate_pinned_register(0, 0); m_tess_coord[0]->pin_live_range(true); m_tess_coord[1] = value_factory().allocate_pinned_register(0, 1); m_tess_coord[1]->pin_live_range(true); } if (m_sv_values.test(es_rel_patch_id)) { m_rel_patch_id = value_factory().allocate_pinned_register(0, 2); m_rel_patch_id->pin_live_range(true); } if (m_sv_values.test(es_primitive_id) || m_vs_as_gs_a) { m_primitive_id = value_factory().allocate_pinned_register(0, 3); m_primitive_id->pin_live_range(true); } return value_factory().next_register_index(); } bool TESShader::process_stage_intrinsic(nir_intrinsic_instr *intr) { switch (intr->intrinsic) { case nir_intrinsic_load_tess_coord_r600: return emit_simple_mov(intr->dest, 0, m_tess_coord[0], pin_none) && emit_simple_mov(intr->dest, 1, m_tess_coord[1], pin_none); case nir_intrinsic_load_primitive_id: return emit_simple_mov(intr->dest, 0, m_primitive_id); case nir_intrinsic_load_tcs_rel_patch_id_r600: return emit_simple_mov(intr->dest, 0, m_rel_patch_id); case nir_intrinsic_store_output: return m_export_processor->store_output(*intr); default: return false; } } void TESShader::do_get_shader_info(r600_shader *sh_info) { sh_info->processor_type = PIPE_SHADER_TESS_EVAL; m_export_processor->get_shader_info(sh_info); } void TESShader::do_finalize() { m_export_processor->finalize(); } bool TESShader::TESShader::read_prop(std::istream& is) { (void)is; return true; } void TESShader::do_print_properties(std::ostream& os) const { (void)os; } }