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
36 namespace r600 {
37
38 using std::priority_queue;
39
VertexShaderFromNir(r600_pipe_shader * sh,r600_pipe_shader_selector & sel,const r600_shader_key & key,struct r600_shader * gs_shader,enum chip_class chip_class)40 VertexShaderFromNir::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
scan_inputs_read(const nir_shader * sh)75 bool 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
do_allocate_reserved_registers()89 bool 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
emit_shader_start()134 void VertexShaderFromNir::emit_shader_start()
135 {
136 m_export_processor->emit_shader_start();
137 }
138
scan_sysvalue_access(nir_instr * instr)139 bool 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
emit_intrinsic_instruction_override(nir_intrinsic_instr * instr)166 bool 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
load_input(nir_intrinsic_instr * instr)187 bool 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
emit_store_local_shared(nir_intrinsic_instr * instr)206 bool 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
do_finalize()225 void VertexShaderFromNir::do_finalize()
226 {
227 m_export_processor->finalize_exports();
228 }
229
230 }
231