1/* -*- mesa-c++ -*- 2 * 3 * Copyright (c) 2018 Collabora LTD 4 * 5 * Author: Gert Wollny <gert.wollny@collabora.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * on the rights to use, copy, modify, merge, publish, distribute, sub 11 * license, and/or sell copies of the Software, and to permit persons to whom 12 * the Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#include "pipe/p_defines.h" 29#include "tgsi/tgsi_from_mesa.h" 30#include "sfn_shader_vertex.h" 31#include "sfn_instruction_lds.h" 32 33#include <queue> 34 35 36namespace r600 { 37 38using std::priority_queue; 39 40VertexShaderFromNir::VertexShaderFromNir(r600_pipe_shader *sh, 41 r600_pipe_shader_selector& sel, 42 const r600_shader_key& key, 43 struct r600_shader* gs_shader, 44 enum chip_class chip_class): 45 VertexStage(PIPE_SHADER_VERTEX, sel, sh->shader, 46 sh->scratch_space_needed, chip_class, key.vs.first_atomic_counter), 47 m_num_clip_dist(0), 48 m_last_param_export(nullptr), 49 m_last_pos_export(nullptr), 50 m_pipe_shader(sh), 51 m_enabled_stream_buffers_mask(0), 52 m_so_info(&sel.so), 53 m_vertex_id(), 54 m_key(key), 55 m_max_attrib(0) 56{ 57 // reg 0 is used in the fetch shader 58 increment_reserved_registers(); 59 60 sh_info().atomic_base = key.vs.first_atomic_counter; 61 sh_info().vs_as_gs_a = m_key.vs.as_gs_a; 62 63 if (key.vs.as_es) { 64 sh->shader.vs_as_es = true; 65 m_export_processor.reset(new VertexStageExportForGS(*this, gs_shader)); 66 } else if (key.vs.as_ls) { 67 sh->shader.vs_as_ls = true; 68 sfn_log << SfnLog::trans << "Start VS for GS\n"; 69 m_export_processor.reset(new VertexStageExportForES(*this)); 70 } else { 71 m_export_processor.reset(new VertexStageExportForFS(*this, &sel.so, sh, key)); 72 } 73} 74 75bool VertexShaderFromNir::scan_inputs_read(const nir_shader *sh) 76{ 77 uint64_t inputs = sh->info.inputs_read; 78 79 while (inputs) { 80 unsigned i = u_bit_scan64(&inputs); 81 if (i < VERT_ATTRIB_MAX) { 82 ++sh_info().ninput; 83 } 84 } 85 m_max_attrib = sh_info().ninput; 86 return true; 87} 88 89bool VertexShaderFromNir::do_allocate_reserved_registers() 90{ 91 /* Since the vertex ID is nearly always used, we add it here as an input so 92 * that the registers used for vertex attributes don't get clobbered by the 93 * register merge step */ 94 auto R0x = new GPRValue(0,0); 95 R0x->set_as_input(); 96 m_vertex_id.reset(R0x); 97 inject_register(0, 0, m_vertex_id, false); 98 99 if (m_key.vs.as_gs_a || m_sv_values.test(es_primitive_id)) { 100 auto R0z = new GPRValue(0,2); 101 R0x->set_as_input(); 102 m_primitive_id.reset(R0z); 103 inject_register(0, 2, m_primitive_id, false); 104 } 105 106 if (m_sv_values.test(es_instanceid)) { 107 auto R0w = new GPRValue(0,3); 108 R0w->set_as_input(); 109 m_instance_id.reset(R0w); 110 inject_register(0, 3, m_instance_id, false); 111 } 112 113 114 if (m_sv_values.test(es_rel_patch_id)) { 115 auto R0y = new GPRValue(0,1); 116 R0y->set_as_input(); 117 m_rel_vertex_id.reset(R0y); 118 inject_register(0, 1, m_rel_vertex_id, false); 119 } 120 121 m_attribs.resize(4 * m_max_attrib + 4); 122 for (unsigned i = 0; i < m_max_attrib + 1; ++i) { 123 for (unsigned k = 0; k < 4; ++k) { 124 auto gpr = std::make_shared<GPRValue>(i + 1, k); 125 gpr->set_as_input(); 126 m_attribs[4 * i + k] = gpr; 127 inject_register(i + 1, k, gpr, false); 128 } 129 } 130 131 return true; 132} 133 134void VertexShaderFromNir::emit_shader_start() 135{ 136 m_export_processor->emit_shader_start(); 137} 138 139bool VertexShaderFromNir::scan_sysvalue_access(nir_instr *instr) 140{ 141 switch (instr->type) { 142 case nir_instr_type_intrinsic: { 143 nir_intrinsic_instr *ii = nir_instr_as_intrinsic(instr); 144 switch (ii->intrinsic) { 145 case nir_intrinsic_load_vertex_id: 146 m_sv_values.set(es_vertexid); 147 break; 148 case nir_intrinsic_load_instance_id: 149 m_sv_values.set(es_instanceid); 150 break; 151 case nir_intrinsic_load_tcs_rel_patch_id_r600: 152 m_sv_values.set(es_rel_patch_id); 153 break; 154 case nir_intrinsic_store_output: 155 m_export_processor->scan_store_output(ii); 156 default: 157 ; 158 } 159 } 160 default: 161 ; 162 } 163 return true; 164} 165 166bool VertexShaderFromNir::emit_intrinsic_instruction_override(nir_intrinsic_instr* instr) 167{ 168 switch (instr->intrinsic) { 169 case nir_intrinsic_load_vertex_id: 170 return load_preloaded_value(instr->dest, 0, m_vertex_id); 171 case nir_intrinsic_load_tcs_rel_patch_id_r600: 172 return load_preloaded_value(instr->dest, 0, m_rel_vertex_id); 173 case nir_intrinsic_load_instance_id: 174 return load_preloaded_value(instr->dest, 0, m_instance_id); 175 case nir_intrinsic_store_local_shared_r600: 176 return emit_store_local_shared(instr); 177 case nir_intrinsic_store_output: 178 return m_export_processor->store_output(instr); 179 case nir_intrinsic_load_input: 180 return load_input(instr); 181 182 default: 183 return false; 184 } 185} 186 187bool VertexShaderFromNir::load_input(nir_intrinsic_instr* instr) 188{ 189 unsigned location = nir_intrinsic_base(instr); 190 191 if (location < VERT_ATTRIB_MAX) { 192 for (unsigned i = 0; i < nir_dest_num_components(instr->dest); ++i) { 193 auto src = m_attribs[4 * location + i]; 194 195 if (i == 0) 196 set_input(location, src); 197 198 load_preloaded_value(instr->dest, i, src, i == (unsigned)(instr->num_components - 1)); 199 } 200 return true; 201 } 202 fprintf(stderr, "r600-NIR: Unimplemented load_deref for %d\n", location); 203 return false; 204} 205 206bool VertexShaderFromNir::emit_store_local_shared(nir_intrinsic_instr* instr) 207{ 208 unsigned write_mask = nir_intrinsic_write_mask(instr); 209 210 auto address = from_nir(instr->src[1], 0); 211 int swizzle_base = (write_mask & 0x3) ? 0 : 2; 212 write_mask |= write_mask >> 2; 213 214 auto value = from_nir(instr->src[0], swizzle_base); 215 if (!(write_mask & 2)) { 216 emit_instruction(new LDSWriteInstruction(address, 1, value)); 217 } else { 218 auto value1 = from_nir(instr->src[0], swizzle_base + 1); 219 emit_instruction(new LDSWriteInstruction(address, 1, value, value1)); 220 } 221 222 return true; 223} 224 225void VertexShaderFromNir::do_finalize() 226{ 227 m_export_processor->finalize_exports(); 228} 229 230} 231