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_emittexinstruction.h"
28 #include "sfn_shader_base.h"
29 #include "sfn_instruction_fetch.h"
30
31 namespace r600 {
32
EmitTexInstruction(ShaderFromNirProcessor & processor)33 EmitTexInstruction::EmitTexInstruction(ShaderFromNirProcessor &processor):
34 EmitInstruction (processor)
35 {
36 }
37
do_emit(nir_instr * instr)38 bool EmitTexInstruction::do_emit(nir_instr* instr)
39 {
40 nir_tex_instr* ir = nir_instr_as_tex(instr);
41
42 TexInputs src;
43 if (!get_inputs(*ir, src))
44 return false;
45
46 if (ir->sampler_dim == GLSL_SAMPLER_DIM_CUBE) {
47 switch (ir->op) {
48 case nir_texop_tex:
49 return emit_cube_tex(ir, src);
50 case nir_texop_txf:
51 return emit_cube_txf(ir, src);
52 case nir_texop_txb:
53 return emit_cube_txb(ir, src);
54 case nir_texop_txl:
55 return emit_cube_txl(ir, src);
56 case nir_texop_txs:
57 return emit_tex_txs(ir, src, {0,1,2,3});
58 case nir_texop_txd:
59 return emit_cube_txd(ir, src);
60 case nir_texop_lod:
61 return emit_cube_lod(ir, src);
62 case nir_texop_tg4:
63 return emit_cube_tg4(ir, src);
64 case nir_texop_query_levels:
65 return emit_tex_txs(ir, src, {3,7,7,7});
66 default:
67 return false;
68 }
69 } else if (ir->sampler_dim == GLSL_SAMPLER_DIM_BUF) {
70 switch (ir->op) {
71 case nir_texop_txf:
72 return emit_buf_txf(ir, src);
73 case nir_texop_txs:
74 return emit_tex_txs(ir, src, {0,1,2,3});
75 default:
76 return false;
77 }
78 } else {
79 switch (ir->op) {
80 case nir_texop_tex:
81 return emit_tex_tex(ir, src);
82 case nir_texop_txf:
83 return emit_tex_txf(ir, src);
84 case nir_texop_txb:
85 return emit_tex_txb(ir, src);
86 case nir_texop_txl:
87 return emit_tex_txl(ir, src);
88 case nir_texop_txd:
89 return emit_tex_txd(ir, src);
90 case nir_texop_txs:
91 return emit_tex_txs(ir, src, {0,1,2,3});
92 case nir_texop_lod:
93 return emit_tex_lod(ir, src);
94 case nir_texop_tg4:
95 return emit_tex_tg4(ir, src);
96 case nir_texop_txf_ms:
97 return emit_tex_txf_ms(ir, src);
98 case nir_texop_query_levels:
99 return emit_tex_txs(ir, src, {3,7,7,7});
100 case nir_texop_texture_samples:
101 return emit_tex_texture_samples(ir, src, {3,7,7,7});
102 default:
103
104 return false;
105 }
106 }
107 }
108
emit_cube_txf(UNUSED nir_tex_instr * instr,UNUSED TexInputs & src)109 bool EmitTexInstruction::emit_cube_txf(UNUSED nir_tex_instr* instr, UNUSED TexInputs &src)
110 {
111 return false;
112 }
113
emit_cube_txd(nir_tex_instr * instr,TexInputs & tex_src)114 bool EmitTexInstruction::emit_cube_txd(nir_tex_instr* instr, TexInputs& tex_src)
115 {
116
117 assert(instr->src[0].src.is_ssa);
118
119 r600::sfn_log << SfnLog::instr << "emit '"
120 << *reinterpret_cast<nir_instr*>(instr)
121 << "' (" << __func__ << ")\n";
122
123 auto tex_op = TexInstruction::sample_g;
124
125 std::array<PValue, 4> v;
126 for (int i = 0; i < 4; ++i)
127 v[i] = from_nir(instr->dest, i);
128
129 GPRVector cubed(v);
130 emit_cube_prep(tex_src.coord, cubed, instr->is_array);
131
132 std::array<PValue,4> dst_elms;
133 std::array<PValue,4> src_elms;
134
135 const uint16_t lookup[4] = {1, 0, 3, 2};
136 for (uint16_t i = 0; i < 4; ++i) {
137 dst_elms[i] = v[i];
138 src_elms[i] = cubed.reg_i(lookup[i]);
139 }
140
141 GPRVector empty_dst(0, {7,7,7,7});
142
143 if (instr->is_shadow) {
144 emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
145 {alu_last_instr, alu_write}));
146 tex_op = TexInstruction::sample_c_g;
147 }
148
149
150 PValue half(new LiteralValue(0.5f));
151 for (int i = 0; i < 3; ++i) {
152 emit_instruction(new AluInstruction(op2_mul_ieee, tex_src.ddx.reg_i(i), {tex_src.ddx.reg_i(i), half},
153 {alu_last_instr, alu_write}));
154 }
155 for (int i = 0; i < 3; ++i) {
156 emit_instruction(new AluInstruction(op2_mul_ieee, tex_src.ddy.reg_i(i), {tex_src.ddy.reg_i(i), half},
157 {alu_last_instr, alu_write}));
158 }
159
160 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
161 assert(!sampler.indirect);
162
163 TexInstruction *irgh = new TexInstruction(TexInstruction::set_gradient_h, empty_dst, tex_src.ddx,
164 sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
165 irgh->set_dest_swizzle({7,7,7,7});
166
167 TexInstruction *irgv = new TexInstruction(TexInstruction::set_gradient_v, empty_dst, tex_src.ddy,
168 sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
169 irgv->set_dest_swizzle({7,7,7,7});
170
171 GPRVector dst(dst_elms);
172 GPRVector src(src_elms);
173 TexInstruction *ir = new TexInstruction(tex_op, dst, src, instr->sampler_index,
174 sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
175
176 set_rect_coordinate_flags(instr, ir);
177 //set_offsets(ir, tex_src.offset);
178
179 emit_instruction(irgh);
180 emit_instruction(irgv);
181 emit_instruction(ir);
182 return true;
183 }
184
185
emit_cube_txl(nir_tex_instr * instr,TexInputs & tex_src)186 bool EmitTexInstruction::emit_cube_txl(nir_tex_instr* instr, TexInputs& tex_src)
187 {
188 assert(instr->src[0].src.is_ssa);
189
190 if (instr->is_shadow)
191 return false;
192
193 r600::sfn_log << SfnLog::instr << "emit '"
194 << *reinterpret_cast<nir_instr*>(instr)
195 << "' (" << __func__ << ")\n";
196
197 std::array<PValue, 4> v;
198 for (int i = 0; i < 4; ++i)
199 v[i] = from_nir(instr->dest, i);
200
201 GPRVector cubed(v);
202 emit_cube_prep(tex_src.coord, cubed, instr->is_array);
203
204 std::array<PValue,4> dst_elms;
205 std::array<PValue,4> src_elms;
206
207 const uint16_t lookup[4] = {1, 0, 3, 2};
208 for (uint16_t i = 0; i < 4; ++i) {
209 dst_elms[i] = v[i];
210 src_elms[i] = cubed.reg_i(lookup[i]);
211 }
212
213 auto *ir = new AluInstruction(op1_mov, src_elms[3], tex_src.lod,
214 {alu_last_instr, alu_write});
215 emit_instruction(ir);
216
217 GPRVector src(src_elms);
218 GPRVector dst(dst_elms);
219
220 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
221 assert(!sampler.indirect);
222
223 auto tir = new TexInstruction(TexInstruction::sample_l, dst, src,
224 sampler.id,sampler.id + R600_MAX_CONST_BUFFERS,
225 tex_src.sampler_offset);
226
227 if (instr->is_array)
228 tir->set_flag(TexInstruction::z_unnormalized);
229
230 emit_instruction(tir);
231 return true;
232 }
233
emit_cube_lod(nir_tex_instr * instr,TexInputs & src)234 bool EmitTexInstruction::emit_cube_lod(nir_tex_instr* instr, TexInputs& src)
235 {
236 auto tex_op = TexInstruction::get_tex_lod;
237
238 std::array<PValue, 4> v;
239 for (int i = 0; i < 4; ++i)
240 v[i] = from_nir(instr->dest, i);
241
242 GPRVector cubed(v);
243 emit_cube_prep(src.coord, cubed, instr->is_array);
244
245 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
246 assert(!sampler.indirect);
247
248 auto dst = make_dest(*instr);
249 auto irt = new TexInstruction(tex_op, dst, cubed, sampler.id,
250 sampler.id + R600_MAX_CONST_BUFFERS,
251 src.sampler_offset);
252
253 emit_instruction(irt);
254 return true;
255
256 }
257
258
emit_cube_txb(nir_tex_instr * instr,TexInputs & tex_src)259 bool EmitTexInstruction::emit_cube_txb(nir_tex_instr* instr, TexInputs& tex_src)
260 {
261 assert(instr->src[0].src.is_ssa);
262
263 r600::sfn_log << SfnLog::instr << "emit '"
264 << *reinterpret_cast<nir_instr*>(instr)
265 << "' (" << __func__ << ")\n";
266
267 std::array<PValue, 4> v;
268 for (int i = 0; i < 4; ++i)
269 v[i] = from_nir(instr->dest, i);
270
271 GPRVector cubed(v);
272 emit_cube_prep(tex_src.coord, cubed, instr->is_array);
273
274 std::array<PValue,4> dst_elms;
275 std::array<PValue,4> src_elms;
276
277 const uint16_t lookup[4] = {1, 0, 3, 2};
278 for (uint16_t i = 0; i < 4; ++i) {
279 dst_elms[i] = v[i];
280 src_elms[i] = v[lookup[i]];
281 }
282
283 GPRVector src(src_elms);
284 GPRVector dst(dst_elms);
285
286 auto tex_op = TexInstruction::sample_lb;
287 if (!instr->is_shadow) {
288 emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.bias,
289 {alu_last_instr, alu_write}));
290 } else {
291 emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
292 {alu_last_instr, alu_write}));
293 tex_op = TexInstruction::sample_c_lb;
294 }
295
296 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
297 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
298
299 auto tir = new TexInstruction(tex_op, dst, src,
300 sampler.id,
301 sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
302 emit_instruction(tir);
303 return true;
304
305 }
306
emit_cube_tex(nir_tex_instr * instr,TexInputs & tex_src)307 bool EmitTexInstruction::emit_cube_tex(nir_tex_instr* instr, TexInputs& tex_src)
308 {
309 std::array<PValue, 4> v;
310 for (int i = 0; i < 4; ++i)
311 v[i] = from_nir(instr->dest, i);
312
313 auto tex_op = TexInstruction::sample;
314 GPRVector cubed(v);
315 emit_cube_prep(tex_src.coord, cubed, instr->is_array);
316
317 std::array<PValue,4> dst_elms;
318 std::array<PValue,4> src_elms;
319
320 const uint16_t lookup[4] = {1, 0, 3, 2};
321 for (uint16_t i = 0; i < 4; ++i) {
322 dst_elms[i] = v[i];
323 src_elms[i] = v[lookup[i]];
324 }
325
326 if (instr->is_shadow) {
327 emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
328 {alu_last_instr, alu_write}));
329 tex_op = TexInstruction::sample_c;
330 }
331
332 GPRVector dst(dst_elms);
333 GPRVector src(src_elms);
334
335 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
336 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
337
338 auto tir = new TexInstruction(tex_op, dst, src,
339 sampler.id,
340 sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
341 if (instr->is_array)
342 tir->set_flag(TexInstruction::z_unnormalized);
343
344 emit_instruction(tir);
345 return true;
346
347 }
348
emit_cube_prep(const GPRVector & coord,GPRVector & cubed,bool is_array)349 bool EmitTexInstruction::emit_cube_prep(const GPRVector& coord, GPRVector& cubed, bool is_array)
350 {
351 AluInstruction *ir = nullptr;
352 const uint16_t src0_chan[4] = {2, 2, 0, 1};
353 const uint16_t src1_chan[4] = {1, 0, 2, 2};
354
355 for (int i = 0; i < 4; ++i) {
356 ir = new AluInstruction(op2_cube, cubed.reg_i(i), coord.reg_i(src0_chan[i]),
357 coord.reg_i(src1_chan[i]), {alu_write});
358
359 emit_instruction(ir);
360 }
361 ir->set_flag(alu_last_instr);
362
363 ir = new AluInstruction(op1_recip_ieee, cubed.reg_i(2), cubed.reg_i(2), {alu_write, alu_last_instr});
364 ir->set_flag(alu_src0_abs);
365 emit_instruction(ir);
366
367 PValue one_p_5(new LiteralValue(1.5f));
368 for (int i = 0; i < 2; ++i) {
369 ir = new AluInstruction(op3_muladd, cubed.reg_i(i), cubed.reg_i(i), cubed.reg_i(2),
370 one_p_5, {alu_write});
371 emit_instruction(ir);
372 }
373 ir->set_flag(alu_last_instr);
374
375 if (is_array) {
376 auto face = cubed.reg_i(3);
377 PValue array_index = get_temp_register();
378
379 ir = new AluInstruction(op1_rndne, array_index, coord.reg_i(3), {alu_write, alu_last_instr});
380 emit_instruction(ir);
381
382 ir = new AluInstruction(op2_max, array_index, {array_index, Value::zero}, {alu_write, alu_last_instr});
383 emit_instruction(ir);
384
385 ir = new AluInstruction(op3_muladd, face, {array_index, PValue (new LiteralValue(8.0f)), face},
386 {alu_write, alu_last_instr});
387 emit_instruction(ir);
388 }
389
390 return true;
391 }
392
emit_buf_txf(nir_tex_instr * instr,TexInputs & src)393 bool EmitTexInstruction::emit_buf_txf(nir_tex_instr* instr, TexInputs &src)
394 {
395 auto dst = make_dest(*instr);
396
397 auto ir = new FetchInstruction(vc_fetch, no_index_offset, dst, src.coord.reg_i(0), 0,
398 instr->texture_index + R600_MAX_CONST_BUFFERS,
399 src.texture_offset, bim_none);
400 ir->set_flag(vtx_use_const_field);
401 emit_instruction(ir);
402 return true;
403 }
404
emit_tex_tex(nir_tex_instr * instr,TexInputs & src)405 bool EmitTexInstruction::emit_tex_tex(nir_tex_instr* instr, TexInputs& src)
406 {
407
408 r600::sfn_log << SfnLog::instr << "emit '"
409 << *reinterpret_cast<nir_instr*>(instr)
410 << "' (" << __func__ << ")\n";
411
412 auto tex_op = TexInstruction::sample;
413
414 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
415 assert(!sampler.indirect);
416
417 if (instr->is_shadow) {
418 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
419 {alu_last_instr, alu_write}));
420 tex_op = TexInstruction::sample_c;
421 }
422
423 auto dst = make_dest(*instr);
424 auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
425 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
426 if (instr->is_array)
427 handle_array_index(*instr, src.coord, irt);
428
429 set_rect_coordinate_flags(instr, irt);
430 set_offsets(irt, src.offset);
431
432 emit_instruction(irt);
433 return true;
434 }
435
emit_tex_txd(nir_tex_instr * instr,TexInputs & src)436 bool EmitTexInstruction::emit_tex_txd(nir_tex_instr* instr, TexInputs& src)
437 {
438 r600::sfn_log << SfnLog::instr << "emit '"
439 << *reinterpret_cast<nir_instr*>(instr)
440 << "' (" << __func__ << ")\n";
441
442 auto tex_op = TexInstruction::sample_g;
443 auto dst = make_dest(*instr);
444
445 GPRVector empty_dst(0,{7,7,7,7});
446
447 if (instr->is_shadow) {
448 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
449 {alu_last_instr, alu_write}));
450 tex_op = TexInstruction::sample_c_g;
451 }
452
453 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
454 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
455
456 TexInstruction *irgh = new TexInstruction(TexInstruction::set_gradient_h, empty_dst, src.ddx,
457 sampler.id,
458 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
459 irgh->set_dest_swizzle({7,7,7,7});
460
461 TexInstruction *irgv = new TexInstruction(TexInstruction::set_gradient_v, empty_dst, src.ddy,
462 sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
463 irgv->set_dest_swizzle({7,7,7,7});
464
465 TexInstruction *ir = new TexInstruction(tex_op, dst, src.coord, sampler.id,
466 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
467 if (instr->is_array)
468 handle_array_index(*instr, src.coord, ir);
469
470 set_rect_coordinate_flags(instr, ir);
471 set_offsets(ir, src.offset);
472
473 emit_instruction(irgh);
474 emit_instruction(irgv);
475 emit_instruction(ir);
476 return true;
477 }
478
emit_tex_txf(nir_tex_instr * instr,TexInputs & src)479 bool EmitTexInstruction::emit_tex_txf(nir_tex_instr* instr, TexInputs& src)
480 {
481 r600::sfn_log << SfnLog::instr << "emit '"
482 << *reinterpret_cast<nir_instr*>(instr)
483 << "' (" << __func__ << ")\n";
484
485 auto dst = make_dest(*instr);
486
487 if (*src.coord.reg_i(3) != *src.lod) {
488 if (src.coord.sel() != src.lod->sel())
489 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.lod, {alu_write, alu_last_instr}));
490 else
491 src.coord.set_reg_i(3, src.lod);
492 }
493
494 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
495 assert(!sampler.indirect);
496
497 /* txf doesn't need rounding for the array index, but 1D has the array index
498 * in the z component */
499 if (instr->is_array && instr->sampler_dim == GLSL_SAMPLER_DIM_1D)
500 src.coord.set_reg_i(2, src.coord.reg_i(1));
501
502 auto tex_ir = new TexInstruction(TexInstruction::ld, dst, src.coord,
503 sampler.id,
504 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
505
506
507 if (src.offset) {
508 assert(src.offset->is_ssa);
509 AluInstruction *ir = nullptr;
510 for (unsigned i = 0; i < src.offset->ssa->num_components; ++i) {
511 ir = new AluInstruction(op2_add_int, src.coord.reg_i(i),
512 {src.coord.reg_i(i), from_nir(*src.offset, i, i)}, {alu_write});
513 emit_instruction(ir);
514 }
515 if (ir)
516 ir->set_flag(alu_last_instr);
517 }
518
519 emit_instruction(tex_ir);
520 return true;
521 }
522
emit_tex_lod(nir_tex_instr * instr,TexInputs & src)523 bool EmitTexInstruction::emit_tex_lod(nir_tex_instr* instr, TexInputs& src)
524 {
525 auto tex_op = TexInstruction::get_tex_lod;
526
527 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
528 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
529
530 auto dst = make_dest(*instr);
531 auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
532 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
533 irt->set_dest_swizzle({1,0,7,7});
534 emit_instruction(irt);
535 return true;
536
537 }
538
emit_tex_txl(nir_tex_instr * instr,TexInputs & src)539 bool EmitTexInstruction::emit_tex_txl(nir_tex_instr* instr, TexInputs& src)
540 {
541 r600::sfn_log << SfnLog::instr << "emit '"
542 << *reinterpret_cast<nir_instr*>(instr)
543 << "' (" << __func__ << ")\n";
544
545 auto tex_op = TexInstruction::sample_l;
546 if (instr->is_shadow) {
547 if (src.coord.sel() != src.comperator->sel())
548 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(2), src.comperator, {alu_write}));
549 else
550 src.coord.set_reg_i(2, src.comperator);
551 tex_op = TexInstruction::sample_c_l;
552 }
553
554 if (src.coord.sel() != src.lod->sel())
555 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.lod, {last_write}));
556 else
557 src.coord.set_reg_i(3, src.lod);
558
559 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
560 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
561
562 auto dst = make_dest(*instr);
563 auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
564 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
565
566 if (instr->is_array)
567 handle_array_index(*instr, src.coord, irt);
568
569 set_rect_coordinate_flags(instr, irt);
570 set_offsets(irt, src.offset);
571
572 emit_instruction(irt);
573 return true;
574 }
575
emit_tex_txb(nir_tex_instr * instr,TexInputs & src)576 bool EmitTexInstruction::emit_tex_txb(nir_tex_instr* instr, TexInputs& src)
577 {
578 auto tex_op = TexInstruction::sample_lb;
579
580 std::array<uint8_t, 4> in_swizzle = {0,1,2,3};
581
582 if (instr->is_shadow) {
583 if (src.coord.sel() != src.comperator->sel())
584 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(2), src.comperator, {alu_write}));
585 else
586 src.coord.set_reg_i(2, src.comperator);
587 tex_op = TexInstruction::sample_c_lb;
588 }
589
590 if (src.coord.sel() != src.bias->sel())
591 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.bias, {last_write}));
592 else
593 src.coord.set_reg_i(3, src.bias);
594
595 GPRVector tex_src(src.coord, in_swizzle);
596
597 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
598 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
599
600 auto dst = make_dest(*instr);
601 auto irt = new TexInstruction(tex_op, dst, tex_src, sampler.id,
602 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
603 if (instr->is_array)
604 handle_array_index(*instr, tex_src, irt);
605
606 set_rect_coordinate_flags(instr, irt);
607 set_offsets(irt, src.offset);
608
609 emit_instruction(irt);
610 return true;
611 }
612
emit_tex_txs(nir_tex_instr * instr,TexInputs & tex_src,const std::array<int,4> & dest_swz)613 bool EmitTexInstruction::emit_tex_txs(nir_tex_instr* instr, TexInputs& tex_src,
614 const std::array<int,4>& dest_swz)
615 {
616 std::array<PValue,4> dst_elms;
617 std::array<PValue,4> src_elms;
618
619 for (uint16_t i = 0; i < 4; ++i) {
620 dst_elms[i] = from_nir(instr->dest, (i < instr->dest.ssa.num_components) ? i : 7);
621 }
622
623 GPRVector dst(dst_elms);
624
625 if (instr->sampler_dim == GLSL_SAMPLER_DIM_BUF) {
626 emit_instruction(new FetchInstruction(dst, PValue(new GPRValue(0, 7)),
627 instr->sampler_index + R600_MAX_CONST_BUFFERS,
628 bim_none));
629 } else {
630 for (uint16_t i = 0; i < 4; ++i)
631 src_elms[i] = tex_src.lod;
632 GPRVector src(src_elms);
633
634 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
635 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
636
637 auto ir = new TexInstruction(TexInstruction::get_resinfo, dst, src,
638 sampler.id,
639 sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
640 ir->set_dest_swizzle(dest_swz);
641 emit_instruction(ir);
642 }
643
644 return true;
645
646 }
647
emit_tex_texture_samples(nir_tex_instr * instr,TexInputs & src,const std::array<int,4> & dest_swz)648 bool EmitTexInstruction::emit_tex_texture_samples(nir_tex_instr* instr, TexInputs& src,
649 const std::array<int, 4> &dest_swz)
650 {
651 GPRVector dest = vec_from_nir(instr->dest, nir_dest_num_components(instr->dest));
652 GPRVector help{0,{4,4,4,4}};
653
654 auto dyn_offset = PValue();
655 int res_id = R600_MAX_CONST_BUFFERS + instr->sampler_index;
656
657 auto ir = new TexInstruction(TexInstruction::get_nsampled, dest, help,
658 0, res_id, src.sampler_offset);
659 ir->set_dest_swizzle(dest_swz);
660 emit_instruction(ir);
661 return true;
662 }
663
emit_tex_tg4(nir_tex_instr * instr,TexInputs & src)664 bool EmitTexInstruction::emit_tex_tg4(nir_tex_instr* instr, TexInputs& src)
665 {
666 r600::sfn_log << SfnLog::instr << "emit '"
667 << *reinterpret_cast<nir_instr*>(instr)
668 << "' (" << __func__ << ")\n";
669
670 TexInstruction *set_ofs = nullptr;
671
672 auto tex_op = TexInstruction::gather4;
673
674 if (instr->is_shadow) {
675 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
676 {alu_last_instr, alu_write}));
677 tex_op = TexInstruction::gather4_c;
678 }
679
680 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
681 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
682
683 bool literal_offset = false;
684 if (src.offset) {
685 literal_offset = nir_src_as_const_value(*src.offset) != 0;
686 r600::sfn_log << SfnLog::tex << " really have offsets and they are " <<
687 (literal_offset ? "literal" : "varying") <<
688 "\n";
689
690 if (!literal_offset) {
691 GPRVector::Swizzle swizzle = {4,4,4,4};
692 for (unsigned i = 0; i < instr->coord_components; ++i)
693 swizzle[i] = i;
694
695 int noffsets = instr->coord_components;
696 if (instr->is_array)
697 --noffsets;
698
699 auto ofs = vec_from_nir_with_fetch_constant(*src.offset,
700 ( 1 << noffsets) - 1,
701 swizzle);
702 GPRVector dummy(0, {7,7,7,7});
703 tex_op = (tex_op == TexInstruction::gather4_c) ?
704 TexInstruction::gather4_c_o : TexInstruction::gather4_o;
705
706 set_ofs = new TexInstruction(TexInstruction::set_offsets, dummy,
707 ofs, sampler.id,
708 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
709 set_ofs->set_dest_swizzle({7,7,7,7});
710 }
711 }
712
713
714 /* pre CAYMAN needs swizzle */
715 auto dst = make_dest(*instr);
716 auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
717 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
718
719 irt->set_dest_swizzle({1,2,0,3});
720 irt->set_gather_comp(instr->component);
721
722 if (instr->is_array)
723 handle_array_index(*instr, src.coord, irt);
724
725 if (literal_offset) {
726 r600::sfn_log << SfnLog::tex << "emit literal offsets\n";
727 set_offsets(irt, src.offset);
728 }
729
730 set_rect_coordinate_flags(instr, irt);
731
732 if (set_ofs)
733 emit_instruction(set_ofs);
734
735 emit_instruction(irt);
736 return true;
737 }
738
emit_cube_tg4(nir_tex_instr * instr,TexInputs & tex_src)739 bool EmitTexInstruction::emit_cube_tg4(nir_tex_instr* instr, TexInputs& tex_src)
740 {
741 std::array<PValue, 4> v;
742 for (int i = 0; i < 4; ++i)
743 v[i] = from_nir(instr->dest, i);
744
745 auto tex_op = TexInstruction::gather4;
746 GPRVector cubed(v);
747 emit_cube_prep(tex_src.coord, cubed, instr->is_array);
748
749 std::array<PValue,4> dst_elms;
750 std::array<PValue,4> src_elms;
751
752 const uint16_t lookup[4] = {1, 0, 3, 2};
753 for (uint16_t i = 0; i < 4; ++i) {
754 dst_elms[i] = v[i];
755 src_elms[i] = v[lookup[i]];
756 }
757
758 if (instr->is_shadow) {
759 emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
760 {alu_last_instr, alu_write}));
761 tex_op = TexInstruction::gather4_c;
762 }
763
764 GPRVector dst(dst_elms);
765 GPRVector src(src_elms);
766
767 auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
768 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
769
770 auto tir = new TexInstruction(tex_op, dst, src, sampler.id,
771 sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
772
773 tir->set_gather_comp(instr->component);
774
775 tir->set_dest_swizzle({1, 2, 0, 3});
776
777 if (instr->is_array)
778 tir->set_flag(TexInstruction::z_unnormalized);
779
780 emit_instruction(tir);
781 return true;
782 }
783
emit_tex_txf_ms(nir_tex_instr * instr,TexInputs & src)784 bool EmitTexInstruction::emit_tex_txf_ms(nir_tex_instr* instr, TexInputs& src)
785 {
786 assert(instr->src[0].src.is_ssa);
787
788 r600::sfn_log << SfnLog::instr << "emit '"
789 << *reinterpret_cast<nir_instr*>(instr)
790 << "' (" << __func__ << ")\n";
791
792 auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
793 assert(!sampler.indirect && "Indirect sampler selection not yet supported");
794
795 int sample_id = allocate_temp_register();
796
797 GPRVector sample_id_dest(sample_id, {0,7,7,7});
798 PValue help(new GPRValue(sample_id, 1));
799
800 /* FIXME: Texture destination registers must be handled differently,
801 * because the swizzle identfies which source componnet has to be written
802 * at a certain position, and the target register is actually different.
803 * At this point we just add a helper register, but for later work (scheduling
804 * and optimization on the r600 IR level, this needs to be implemented
805 * differently */
806
807
808 emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3),
809 src.ms_index,
810 {alu_write, alu_last_instr}));
811
812 auto tex_sample_id_ir = new TexInstruction(TexInstruction::ld, sample_id_dest, src.coord,
813 sampler.id,
814 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
815 tex_sample_id_ir->set_flag(TexInstruction::x_unnormalized);
816 tex_sample_id_ir->set_flag(TexInstruction::y_unnormalized);
817 tex_sample_id_ir->set_flag(TexInstruction::z_unnormalized);
818 tex_sample_id_ir->set_flag(TexInstruction::w_unnormalized);
819 tex_sample_id_ir->set_inst_mode(1);
820
821 emit_instruction(tex_sample_id_ir);
822
823
824 if (src.ms_index->type() != Value::literal ||
825 static_cast<const LiteralValue&>(*src.ms_index).value() != 0) {
826 emit_instruction(new AluInstruction(op2_lshl_int, help,
827 src.ms_index, literal(2),
828 {alu_write, alu_last_instr}));
829
830 emit_instruction(new AluInstruction(op2_lshr_int, sample_id_dest.reg_i(0),
831 {sample_id_dest.reg_i(0), help},
832 {alu_write, alu_last_instr}));
833 }
834
835 emit_instruction(new AluInstruction(op2_and_int, src.coord.reg_i(3),
836 {sample_id_dest.reg_i(0), PValue(new LiteralValue(15))},
837 {alu_write, alu_last_instr}));
838
839 auto dst = make_dest(*instr);
840
841 /* txf doesn't need rounding for the array index, but 1D has the array index
842 * in the z component */
843 if (instr->is_array && instr->sampler_dim == GLSL_SAMPLER_DIM_1D)
844 src.coord.set_reg_i(2, src.coord.reg_i(1));
845
846 auto tex_ir = new TexInstruction(TexInstruction::ld, dst, src.coord,
847 sampler.id,
848 sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
849
850
851 if (src.offset) {
852 assert(src.offset->is_ssa);
853 AluInstruction *ir = nullptr;
854 for (unsigned i = 0; i < src.offset->ssa->num_components; ++i) {
855 ir = new AluInstruction(op2_add_int, src.coord.reg_i(i),
856 {src.coord.reg_i(i), from_nir(*src.offset, i, i)}, {alu_write});
857 emit_instruction(ir);
858 }
859 if (ir)
860 ir->set_flag(alu_last_instr);
861 }
862
863 emit_instruction(tex_ir);
864 return true;
865 }
866
get_inputs(const nir_tex_instr & instr,TexInputs & src)867 bool EmitTexInstruction::get_inputs(const nir_tex_instr& instr, TexInputs &src)
868 {
869 sfn_log << SfnLog::tex << "Get Inputs with " << instr.coord_components << " components\n";
870
871 unsigned grad_components = instr.coord_components;
872 if (instr.is_array)
873 --grad_components;
874
875
876 src.offset = nullptr;
877 bool retval = true;
878 for (unsigned i = 0; i < instr.num_srcs; ++i) {
879 switch (instr.src[i].src_type) {
880 case nir_tex_src_bias:
881 src.bias = from_nir(instr.src[i], 0);
882 break;
883
884 case nir_tex_src_coord: {
885 src.coord = vec_from_nir_with_fetch_constant(instr.src[i].src,
886 (1 << instr.coord_components) - 1,
887 {0,1,2,3});
888 } break;
889 case nir_tex_src_comparator:
890 src.comperator = from_nir(instr.src[i], 0);
891 break;
892 case nir_tex_src_ddx: {
893 sfn_log << SfnLog::tex << "Get DDX ";
894 src.ddx = vec_from_nir_with_fetch_constant(instr.src[i].src,
895 (1 << grad_components) - 1,
896 swizzle_from_comps(grad_components));
897 sfn_log << SfnLog::tex << src.ddx << "\n";
898 } break;
899 case nir_tex_src_ddy:{
900 sfn_log << SfnLog::tex << "Get DDY ";
901 src.ddy = vec_from_nir_with_fetch_constant(instr.src[i].src,
902 (1 << grad_components) - 1,
903 swizzle_from_comps(grad_components));
904 sfn_log << SfnLog::tex << src.ddy << "\n";
905 } break;
906 case nir_tex_src_lod:
907 src.lod = from_nir_with_fetch_constant(instr.src[i].src, 0);
908 break;
909 case nir_tex_src_offset:
910 sfn_log << SfnLog::tex << " -- Find offset\n";
911 src.offset = &instr.src[i].src;
912 break;
913 case nir_tex_src_sampler_deref:
914 src.sampler_deref = get_deref_location(instr.src[i].src);
915 break;
916 case nir_tex_src_texture_deref:
917 src.texture_deref = get_deref_location(instr.src[i].src);
918 break;
919 case nir_tex_src_ms_index:
920 src.ms_index = from_nir(instr.src[i], 0);
921 break;
922 case nir_tex_src_texture_offset:
923 src.texture_offset = from_nir(instr.src[i], 0);
924 break;
925 case nir_tex_src_sampler_offset:
926 src.sampler_offset = from_nir(instr.src[i], 0);
927 break;
928 case nir_tex_src_plane:
929 case nir_tex_src_projector:
930 case nir_tex_src_min_lod:
931 case nir_tex_src_ms_mcs:
932 default:
933 sfn_log << SfnLog::tex << "Texture source type " << instr.src[i].src_type << " not supported\n";
934 retval = false;
935 }
936 }
937 return retval;
938 }
939
make_dest(nir_tex_instr & instr)940 GPRVector EmitTexInstruction::make_dest(nir_tex_instr& instr)
941 {
942 int num_dest_components = instr.dest.is_ssa ? instr.dest.ssa.num_components :
943 instr.dest.reg.reg->num_components;
944 std::array<PValue,4> dst_elms;
945 for (uint16_t i = 0; i < 4; ++i)
946 dst_elms[i] = from_nir(instr.dest, (i < num_dest_components) ? i : 7);
947 return GPRVector(dst_elms);
948 }
949
950
make_dest(nir_tex_instr & instr,const std::array<int,4> & swizzle)951 GPRVector EmitTexInstruction::make_dest(nir_tex_instr& instr,
952 const std::array<int, 4>& swizzle)
953 {
954 int num_dest_components = instr.dest.is_ssa ? instr.dest.ssa.num_components :
955 instr.dest.reg.reg->num_components;
956 std::array<PValue,4> dst_elms;
957 for (uint16_t i = 0; i < 4; ++i) {
958 int k = swizzle[i];
959 dst_elms[i] = from_nir(instr.dest, (k < num_dest_components) ? k : 7);
960 }
961 return GPRVector(dst_elms);
962 }
963
set_rect_coordinate_flags(nir_tex_instr * instr,TexInstruction * ir) const964 void EmitTexInstruction::set_rect_coordinate_flags(nir_tex_instr* instr,
965 TexInstruction* ir) const
966 {
967 if (instr->sampler_dim == GLSL_SAMPLER_DIM_RECT) {
968 ir->set_flag(TexInstruction::x_unnormalized);
969 ir->set_flag(TexInstruction::y_unnormalized);
970 }
971 }
972
set_offsets(TexInstruction * ir,nir_src * offset)973 void EmitTexInstruction::set_offsets(TexInstruction* ir, nir_src *offset)
974 {
975 if (!offset)
976 return;
977
978 assert(offset->is_ssa);
979 auto literal = nir_src_as_const_value(*offset);
980 assert(literal);
981
982 for (int i = 0; i < offset->ssa->num_components; ++i) {
983 ir->set_offset(i, literal[i].i32);
984 }
985 }
986
handle_array_index(const nir_tex_instr & instr,const GPRVector & src,TexInstruction * ir)987 void EmitTexInstruction::handle_array_index(const nir_tex_instr& instr, const GPRVector& src, TexInstruction *ir)
988 {
989 int src_idx = instr.sampler_dim == GLSL_SAMPLER_DIM_1D ? 1 : 2;
990 emit_instruction(new AluInstruction(op1_rndne, src.reg_i(2), src.reg_i(src_idx),
991 {alu_last_instr, alu_write}));
992 ir->set_flag(TexInstruction::z_unnormalized);
993 }
994
995 EmitTexInstruction::SamplerId
get_samplerr_id(int sampler_id,const nir_variable * deref)996 EmitTexInstruction::get_samplerr_id(int sampler_id, const nir_variable *deref)
997 {
998 EmitTexInstruction::SamplerId result = {sampler_id, false};
999
1000 if (deref) {
1001 assert(glsl_type_is_sampler(deref->type));
1002 result.id = deref->data.binding;
1003 }
1004 return result;
1005 }
1006
TexInputs()1007 EmitTexInstruction::TexInputs::TexInputs():
1008 sampler_deref(nullptr),
1009 texture_deref(nullptr),
1010 offset(nullptr)
1011 {
1012 }
1013
1014 }
1015