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