1 /* -*- mesa-c++ -*-
2 *
3 * Copyright (c) 2022 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 #include "sfn_instr_export.h"
28 #include "sfn_shader_tess.h"
29 #include "sfn_shader_vs.h"
30
31
32 #include <sstream>
33
34 namespace r600 {
35
36 using std::string;
37
TCSShader(const r600_shader_key & key)38 TCSShader::TCSShader(const r600_shader_key& key):
39 Shader("TCS"),
40 m_tcs_prim_mode(key.tcs.prim_mode)
41 {
42
43 }
44
do_scan_instruction(nir_instr * instr)45 bool TCSShader::do_scan_instruction(nir_instr *instr)
46 {
47 if (instr->type != nir_instr_type_intrinsic)
48 return false;
49
50 nir_intrinsic_instr *ii = nir_instr_as_intrinsic(instr);
51
52 switch (ii->intrinsic) {
53 case nir_intrinsic_load_primitive_id:
54 m_sv_values.set(es_primitive_id);
55 break;
56 case nir_intrinsic_load_invocation_id:
57 m_sv_values.set(es_invocation_id);
58 break;
59 case nir_intrinsic_load_tcs_rel_patch_id_r600:
60 m_sv_values.set(es_rel_patch_id);
61 break;
62 case nir_intrinsic_load_tcs_tess_factor_base_r600:
63 m_sv_values.set(es_tess_factor_base);
64 break;
65 default:
66 return false;
67 ;
68 }
69 return true;
70 }
71
do_allocate_reserved_registers()72 int TCSShader::do_allocate_reserved_registers()
73 {
74 if (m_sv_values.test(es_primitive_id)) {
75 m_primitive_id = value_factory().allocate_pinned_register(0, 0);
76 m_primitive_id->pin_live_range(true);
77 }
78
79 if (m_sv_values.test(es_invocation_id)) {
80 m_invocation_id = value_factory().allocate_pinned_register(0, 2);
81 m_invocation_id->pin_live_range(true);
82 }
83
84 if (m_sv_values.test(es_rel_patch_id)) {
85 m_rel_patch_id = value_factory().allocate_pinned_register(0, 1);;
86 m_rel_patch_id->pin_live_range(true);
87 }
88
89 if (m_sv_values.test(es_tess_factor_base)) {
90 m_tess_factor_base = value_factory().allocate_pinned_register(0, 3);
91 m_tess_factor_base->pin_live_range(true);
92 }
93
94 return value_factory().next_register_index();;
95 }
96
process_stage_intrinsic(nir_intrinsic_instr * instr)97 bool TCSShader::process_stage_intrinsic(nir_intrinsic_instr *instr)
98 {
99 switch (instr->intrinsic) {
100 case nir_intrinsic_load_tcs_rel_patch_id_r600:
101 return emit_simple_mov(instr->dest, 0, m_rel_patch_id);
102 case nir_intrinsic_load_invocation_id:
103 return emit_simple_mov(instr->dest, 0, m_invocation_id);
104 case nir_intrinsic_load_primitive_id:
105 return emit_simple_mov(instr->dest, 0, m_primitive_id);
106 case nir_intrinsic_load_tcs_tess_factor_base_r600:
107 return emit_simple_mov(instr->dest, 0, m_tess_factor_base);
108 case nir_intrinsic_store_tf_r600:
109 return store_tess_factor(instr);
110 default:
111 return false;
112 }
113 }
114
store_tess_factor(nir_intrinsic_instr * instr)115 bool TCSShader::store_tess_factor(nir_intrinsic_instr* instr)
116 {
117 bool two_parts = nir_src_num_components(instr->src[0]) == 4;
118
119 auto value0 = value_factory().temp_vec4(pin_group, {0, 1, 7, 7});
120 emit_instruction(new AluInstr(op1_mov, value0[0], value_factory().src(instr->src[0], 0),
121 AluInstr::write));
122 emit_instruction(new AluInstr(op1_mov, value0[1], value_factory().src(instr->src[0], 1),
123 two_parts ? AluInstr::write : AluInstr::last_write));
124
125
126 if (two_parts) {
127 auto value1 = value_factory().temp_vec4(pin_group, {2, 3, 7, 7});
128 emit_instruction(new AluInstr(op1_mov, value1[0], value_factory().src(instr->src[0], 2),
129 AluInstr::write));
130 emit_instruction(new AluInstr(op1_mov, value1[1], value_factory().src(instr->src[0], 3),
131 AluInstr::last_write));
132 emit_instruction(new WriteTFInstr(value1));
133 }
134
135 emit_instruction(new WriteTFInstr(value0));
136 return true;
137 }
138
139
do_get_shader_info(r600_shader * sh_info)140 void TCSShader::do_get_shader_info(r600_shader *sh_info)
141 {
142 sh_info->processor_type = PIPE_SHADER_TESS_CTRL;
143 sh_info->tcs_prim_mode = m_tcs_prim_mode;
144 }
145
read_prop(std::istream & is)146 bool TCSShader::read_prop(std::istream& is)
147 {
148 string value;
149 is >> value;
150
151 auto splitpos = value.find(':');
152 assert(splitpos != string::npos);
153
154 std::istringstream ival(value);
155 string name;
156 string val;
157
158 std::getline(ival, name, ':');
159
160 if (name == "TCS_PRIM_MODE")
161 ival >> m_tcs_prim_mode;
162 else
163 return false;
164 return true;
165 }
166
do_print_properties(std::ostream & os) const167 void TCSShader::do_print_properties(std::ostream& os) const
168 {
169 os << "PROP TCS_PRIM_MODE:" << m_tcs_prim_mode << "\n";
170 }
171
TESShader(const pipe_stream_output_info * so_info,const r600_shader * gs_shader,const r600_shader_key & key)172 TESShader::TESShader(const pipe_stream_output_info *so_info, const r600_shader *gs_shader,
173 const r600_shader_key& key):
174 VertexStageShader("TES"),
175 m_vs_as_gs_a(key.vs.as_gs_a),
176 m_tes_as_es(key.tes.as_es)
177 {
178 if (key.tes.as_es)
179 m_export_processor = new VertexExportForGS(this, gs_shader);
180 else
181 m_export_processor = new VertexExportForFs(this, so_info, key);
182 }
183
do_scan_instruction(nir_instr * instr)184 bool TESShader::do_scan_instruction(nir_instr *instr)
185 {
186 if (instr->type != nir_instr_type_intrinsic)
187 return false;
188
189 auto intr = nir_instr_as_intrinsic(instr);
190
191 switch (intr->intrinsic) {
192 case nir_intrinsic_load_tess_coord_r600:
193 m_sv_values.set(es_tess_coord);
194 break;
195 case nir_intrinsic_load_primitive_id:
196 m_sv_values.set(es_primitive_id);
197 break;
198 case nir_intrinsic_load_tcs_rel_patch_id_r600:
199 m_sv_values.set(es_rel_patch_id);
200 break;
201 case nir_intrinsic_store_output: {
202 int driver_location = nir_intrinsic_base(intr);
203 int location = nir_intrinsic_io_semantics(intr).location;
204 auto semantic = r600_get_varying_semantic(location);
205 tgsi_semantic name = (tgsi_semantic)semantic.first;
206 unsigned sid = semantic.second;
207 auto write_mask = nir_intrinsic_write_mask(intr);
208
209 if (location == VARYING_SLOT_LAYER)
210 write_mask = 4;
211
212 ShaderOutput output(driver_location, name, write_mask);
213 output.set_sid(sid);
214
215 switch (location) {
216 case VARYING_SLOT_PSIZ:
217 case VARYING_SLOT_POS:
218 case VARYING_SLOT_CLIP_VERTEX:
219 case VARYING_SLOT_EDGE: {
220 break;
221 }
222 case VARYING_SLOT_CLIP_DIST0:
223 case VARYING_SLOT_CLIP_DIST1:
224 case VARYING_SLOT_VIEWPORT:
225 case VARYING_SLOT_LAYER:
226 case VARYING_SLOT_VIEW_INDEX:
227 default:
228 output.set_is_param(true);
229 }
230 add_output(output);
231 break;
232 }
233 default:
234 return false;
235 }
236 return true;
237 }
238
do_allocate_reserved_registers()239 int TESShader::do_allocate_reserved_registers()
240 {
241 if (m_sv_values.test(es_tess_coord)) {
242 m_tess_coord[0] = value_factory().allocate_pinned_register(0, 0);
243 m_tess_coord[0]->pin_live_range(true);
244 m_tess_coord[1] = value_factory().allocate_pinned_register(0, 1);
245 m_tess_coord[1]->pin_live_range(true);
246 }
247
248 if (m_sv_values.test(es_rel_patch_id)) {
249 m_rel_patch_id = value_factory().allocate_pinned_register(0, 2);
250 m_rel_patch_id->pin_live_range(true);
251 }
252
253 if (m_sv_values.test(es_primitive_id) || m_vs_as_gs_a) {
254 m_primitive_id = value_factory().allocate_pinned_register(0, 3);
255 m_primitive_id->pin_live_range(true);
256 }
257 return value_factory().next_register_index();
258 }
259
process_stage_intrinsic(nir_intrinsic_instr * intr)260 bool TESShader::process_stage_intrinsic(nir_intrinsic_instr *intr)
261 {
262 switch (intr->intrinsic) {
263 case nir_intrinsic_load_tess_coord_r600:
264 return emit_simple_mov(intr->dest, 0, m_tess_coord[0], pin_none) &&
265 emit_simple_mov(intr->dest, 1, m_tess_coord[1], pin_none);
266 case nir_intrinsic_load_primitive_id:
267 return emit_simple_mov(intr->dest, 0, m_primitive_id);
268 case nir_intrinsic_load_tcs_rel_patch_id_r600:
269 return emit_simple_mov(intr->dest, 0, m_rel_patch_id);
270 case nir_intrinsic_store_output:
271 return m_export_processor->store_output(*intr);
272 default:
273 return false;
274 }
275 }
276
do_get_shader_info(r600_shader * sh_info)277 void TESShader::do_get_shader_info(r600_shader *sh_info)
278 {
279 sh_info->processor_type = PIPE_SHADER_TESS_EVAL;
280 m_export_processor->get_shader_info(sh_info);
281 }
282
do_finalize()283 void TESShader::do_finalize()
284 {
285 m_export_processor->finalize();
286 }
287
read_prop(std::istream & is)288 bool TESShader::TESShader::read_prop(std::istream& is)
289 {
290 (void)is;
291 return true;
292 }
293
do_print_properties(std::ostream & os) const294 void TESShader::do_print_properties(std::ostream& os) const
295 {
296 (void)os;
297 }
298
299
300 }
301