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