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#include "sfn_shaderio.h"
28#include "sfn_debug.h"
29#include "tgsi/tgsi_from_mesa.h"
30
31#include <queue>
32
33namespace r600 {
34
35using std::vector;
36using std::priority_queue;
37
38ShaderIO::ShaderIO():
39   m_two_sided(false),
40   m_lds_pos(0)
41{
42
43}
44
45ShaderInput::ShaderInput(tgsi_semantic name):
46   m_name(name),
47   m_gpr(0),
48   m_uses_interpolate_at_centroid(false)
49{
50}
51
52ShaderInput::~ShaderInput()
53{
54}
55
56void ShaderInput::set_lds_pos(UNUSED int lds_pos)
57{
58}
59
60int ShaderInput::ij_index() const
61{
62   return -1;
63}
64
65bool ShaderInput::interpolate() const
66{
67   return false;
68}
69
70int ShaderInput::lds_pos() const
71{
72   return 0;
73}
74
75bool ShaderInput::is_varying() const
76{
77   return false;
78}
79
80void ShaderInput::set_uses_interpolate_at_centroid()
81{
82   m_uses_interpolate_at_centroid = true;
83}
84
85void ShaderInput::set_ioinfo(r600_shader_io& io, int translated_ij_index) const
86{
87   io.name = m_name;
88   io.gpr = m_gpr;
89   io.ij_index = translated_ij_index;
90   io.lds_pos = lds_pos();
91   io.uses_interpolate_at_centroid = m_uses_interpolate_at_centroid;
92
93   set_specific_ioinfo(io);
94}
95
96void ShaderInput::set_specific_ioinfo(UNUSED r600_shader_io& io) const
97{
98}
99
100ShaderInputSystemValue::ShaderInputSystemValue(tgsi_semantic name, int gpr):
101   ShaderInput(name),
102   m_gpr(gpr)
103{
104}
105
106void ShaderInputSystemValue::set_specific_ioinfo(r600_shader_io& io) const
107{
108   io.gpr = m_gpr;
109   io.ij_index = 0;
110}
111
112ShaderInputVarying::ShaderInputVarying(tgsi_semantic _name, int sid, unsigned driver_location,
113                                       unsigned frac, unsigned components,
114                                       tgsi_interpolate_mode interpolate,
115                                       tgsi_interpolate_loc interp_loc):
116   ShaderInput(_name),
117   m_driver_location(driver_location),
118   m_location_frac(frac),
119   m_sid(sid),
120   m_interpolate(interpolate),
121   m_interpolate_loc(interp_loc),
122   m_ij_index(-10),
123   m_lds_pos(0),
124   m_mask(((1 << components) - 1) << frac)
125{
126   evaluate_spi_sid();
127
128   m_ij_index = interpolate == TGSI_INTERPOLATE_LINEAR ? 3 : 0;
129   switch (interp_loc) {
130   case TGSI_INTERPOLATE_LOC_CENTROID: m_ij_index += 2; break;
131   case TGSI_INTERPOLATE_LOC_CENTER: m_ij_index += 1; break;
132   default:
133      ;
134   }
135}
136
137ShaderInputVarying::ShaderInputVarying(tgsi_semantic _name, int sid, nir_variable *input):
138   ShaderInput(_name),
139   m_driver_location(input->data.driver_location),
140   m_location_frac(input->data.location_frac),
141   m_sid(sid),
142   m_ij_index(-10),
143   m_lds_pos(0),
144   m_mask(((1 << input->type->components()) - 1) << input->data.location_frac)
145{
146   sfn_log << SfnLog::io << __func__
147           << "name:" << _name
148           << " sid: " << sid
149           << " op: " << input->data.interpolation;
150
151   evaluate_spi_sid();
152
153   enum glsl_base_type base_type =
154      glsl_get_base_type(glsl_without_array(input->type));
155
156   switch (input->data.interpolation) {
157   case INTERP_MODE_NONE:
158      if (glsl_base_type_is_integer(base_type)) {
159         m_interpolate = TGSI_INTERPOLATE_CONSTANT;
160         break;
161      }
162
163      if (name() == TGSI_SEMANTIC_COLOR) {
164         m_interpolate = TGSI_INTERPOLATE_COLOR;
165         m_ij_index = 0;
166         break;
167      }
168      FALLTHROUGH;
169
170   case INTERP_MODE_SMOOTH:
171      assert(!glsl_base_type_is_integer(base_type));
172
173      m_interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
174      m_ij_index = 0;
175      break;
176
177   case INTERP_MODE_NOPERSPECTIVE:
178      assert(!glsl_base_type_is_integer(base_type));
179
180      m_interpolate = TGSI_INTERPOLATE_LINEAR;
181      m_ij_index = 3;
182      break;
183
184   case INTERP_MODE_FLAT:
185      m_interpolate = TGSI_INTERPOLATE_CONSTANT;
186      break;
187
188   default:
189      m_interpolate = TGSI_INTERPOLATE_CONSTANT;
190      break;
191   }
192
193   if (input->data.sample) {
194      m_interpolate_loc = TGSI_INTERPOLATE_LOC_SAMPLE;
195   } else if (input->data.centroid) {
196      m_interpolate_loc = TGSI_INTERPOLATE_LOC_CENTROID;
197      m_ij_index += 2;
198   } else {
199      m_interpolate_loc = TGSI_INTERPOLATE_LOC_CENTER;
200      m_ij_index += 1;
201   }
202   sfn_log << SfnLog::io
203           << " -> IP:" << m_interpolate
204           << " IJ:" << m_ij_index
205           << "\n";
206}
207
208bool ShaderInputVarying::is_varying() const
209{
210   return true;
211}
212
213void ShaderInputVarying::update_mask(int additional_comps, int frac)
214{
215   m_mask |= ((1 << additional_comps) - 1) << frac;
216}
217
218void ShaderInputVarying::evaluate_spi_sid()
219{
220   switch (name()) {
221   case TGSI_SEMANTIC_PSIZE:
222   case TGSI_SEMANTIC_EDGEFLAG:
223   case TGSI_SEMANTIC_FACE:
224   case TGSI_SEMANTIC_SAMPLEMASK:
225      assert(0 && "System value used as varying");
226      break;
227   case TGSI_SEMANTIC_POSITION:
228      m_spi_sid = 0;
229      break;
230   case TGSI_SEMANTIC_GENERIC:
231   case TGSI_SEMANTIC_TEXCOORD:
232   case TGSI_SEMANTIC_PCOORD:
233      m_spi_sid = m_sid + 1;
234      break;
235   default:
236      /* For non-generic params - pack name and sid into 8 bits */
237      m_spi_sid = (0x80 | (name() << 3) | m_sid) + 1;
238   }
239}
240
241ShaderInputVarying::ShaderInputVarying(tgsi_semantic name,
242                                       const ShaderInputVarying& orig, size_t location):
243   ShaderInput(name),
244   m_driver_location(location),
245   m_location_frac(orig.location_frac()),
246
247   m_sid(orig.m_sid),
248   m_spi_sid(orig.m_spi_sid),
249   m_interpolate(orig.m_interpolate),
250   m_interpolate_loc(orig.m_interpolate_loc),
251   m_ij_index(orig.m_ij_index),
252   m_lds_pos(0),
253   m_mask(0)
254{
255   evaluate_spi_sid();
256}
257
258bool ShaderInputVarying::interpolate() const
259{
260   return m_interpolate > 0;
261}
262
263int ShaderInputVarying::ij_index() const
264{
265   return m_ij_index;
266}
267
268void ShaderInputVarying::set_lds_pos(int lds_pos)
269{
270   m_lds_pos = lds_pos;
271}
272
273int ShaderInputVarying::lds_pos() const
274{
275   return m_lds_pos;
276}
277
278void ShaderInputVarying::set_specific_ioinfo(r600_shader_io& io) const
279{
280   io.interpolate = m_interpolate;
281   io.interpolate_location = m_interpolate_loc;
282   io.sid = m_sid;
283   io.spi_sid = m_spi_sid;
284   set_color_ioinfo(io);
285}
286
287void ShaderInputVarying::set_color_ioinfo(UNUSED r600_shader_io& io) const
288{
289   sfn_log << SfnLog::io << __func__ << " Don't set color_ioinfo\n";
290}
291
292ShaderInputColor::ShaderInputColor(tgsi_semantic name, int sid, nir_variable *input):
293   ShaderInputVarying(name, sid, input),
294   m_back_color_input_idx(0)
295{
296   sfn_log << SfnLog::io << __func__ << "name << " << name << " sid << " << sid << "\n";
297}
298
299ShaderInputColor::ShaderInputColor(tgsi_semantic _name, int sid, unsigned driver_location,
300                                   unsigned frac, unsigned components, tgsi_interpolate_mode interpolate,
301                                   tgsi_interpolate_loc interp_loc):
302   ShaderInputVarying(_name, sid, driver_location,frac, components, interpolate, interp_loc),
303   m_back_color_input_idx(0)
304{
305   sfn_log << SfnLog::io << __func__ << "name << " << _name << " sid << " << sid << "\n";
306}
307
308void ShaderInputColor::set_back_color(unsigned back_color_input_idx)
309{
310   sfn_log << SfnLog::io << "Set back color index " << back_color_input_idx << "\n";
311   m_back_color_input_idx = back_color_input_idx;
312}
313
314void ShaderInputColor::set_color_ioinfo(r600_shader_io& io) const
315{
316   sfn_log << SfnLog::io << __func__ << " set color_ioinfo " << m_back_color_input_idx << "\n";
317   io.back_color_input = m_back_color_input_idx;
318}
319
320size_t ShaderIO::add_input(ShaderInput *input)
321{
322   m_inputs.push_back(PShaderInput(input));
323   return m_inputs.size() - 1;
324}
325
326PShaderInput ShaderIO::find_varying(tgsi_semantic name, int sid)
327{
328   for (auto& a : m_inputs) {
329      if (a->name() == name) {
330         assert(a->is_varying());
331         auto& v = static_cast<ShaderInputVarying&>(*a);
332         if (v.sid() == sid)
333            return a;
334      }
335   }
336   return nullptr;
337}
338
339struct VaryingShaderIOLess {
340   bool operator () (PShaderInput lhs, PShaderInput rhs) const
341   {
342      const ShaderInputVarying& l = static_cast<ShaderInputVarying&>(*lhs);
343      const ShaderInputVarying& r = static_cast<ShaderInputVarying&>(*rhs);
344      return l.location() > r.location();
345   }
346};
347
348void ShaderIO::sort_varying_inputs()
349{
350   priority_queue<PShaderInput, vector<PShaderInput>, VaryingShaderIOLess> q;
351
352   vector<int> idx;
353
354   for (auto i = 0u; i < m_inputs.size(); ++i) {
355      if (m_inputs[i]->is_varying()) {
356         q.push(m_inputs[i]);
357         idx.push_back(i);
358      }
359   }
360
361   auto next_index = idx.begin();
362   while (!q.empty()) {
363      auto si = q.top();
364      q.pop();
365      m_inputs[*next_index++] = si;
366   }
367}
368
369void ShaderIO::update_lds_pos()
370{
371   m_lds_pos = -1;
372   m_ldspos.resize(m_inputs.size());
373   for (auto& i : m_inputs) {
374      if (!i->is_varying())
375         continue;
376
377      auto& v = static_cast<ShaderInputVarying&>(*i);
378      /* There are shaders that miss an input ...*/
379      if (m_ldspos.size() <= static_cast<unsigned>(v.location()))
380          m_ldspos.resize(v.location() + 1);
381   }
382
383   std::fill(m_ldspos.begin(), m_ldspos.end(), -1);
384   for (auto& i : m_inputs) {
385      if (!i->is_varying())
386         continue;
387
388      auto& v = static_cast<ShaderInputVarying&>(*i);
389      if (v.name() == TGSI_SEMANTIC_POSITION)
390         continue;
391
392      if (m_ldspos[v.location()] < 0) {
393         ++m_lds_pos;
394         m_ldspos[v.location()] = m_lds_pos;
395      }
396      v.set_lds_pos(m_lds_pos);
397   }
398   ++m_lds_pos;
399}
400
401std::vector<PShaderInput> &ShaderIO::inputs()
402{
403   return m_inputs;
404}
405
406ShaderInput& ShaderIO::input(size_t k)
407{
408   assert(k < m_inputs.size());
409   return *m_inputs[k];
410}
411
412ShaderInput& ShaderIO::input(size_t driver_loc, int frac)
413{
414   for (auto& i: m_inputs) {
415      if (!i->is_varying())
416         continue;
417
418      auto& v = static_cast<ShaderInputVarying&>(*i);
419      if (v.location() == driver_loc)
420         return v;
421   }
422   return input(driver_loc);
423}
424
425void ShaderIO::set_two_sided()
426{
427   m_two_sided = true;
428}
429
430std::pair<unsigned, unsigned>
431r600_get_varying_semantic(unsigned varying_location)
432{
433   std::pair<unsigned, unsigned> result;
434   tgsi_get_gl_varying_semantic(static_cast<gl_varying_slot>(varying_location),
435                                true, &result.first, &result.second);
436
437   if (result.first == TGSI_SEMANTIC_GENERIC) {
438      result.second += 9;
439   } else if (result.first == TGSI_SEMANTIC_PCOORD) {
440      result.second = 8;
441   }
442   return result;
443}
444
445
446
447}
448
449