3 * Copyright (c) 2018 Collabora LTD
5 * Author: Gert Wollny <gert.wollny@collabora.com>
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:
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
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.
27 #include "sfn_emittexinstruction.h"
28 #include "sfn_shader_base.h"
29 #include "sfn_instruction_fetch.h"
33 EmitTexInstruction::EmitTexInstruction(ShaderFromNirProcessor
&processor
):
34 EmitInstruction (processor
)
38 bool EmitTexInstruction::do_emit(nir_instr
* instr
)
40 nir_tex_instr
* ir
= nir_instr_as_tex(instr
);
43 if (!get_inputs(*ir
, src
))
46 if (ir
->sampler_dim
== GLSL_SAMPLER_DIM_CUBE
) {
49 return emit_cube_tex(ir
, src
);
51 return emit_cube_txf(ir
, src
);
53 return emit_cube_txb(ir
, src
);
55 return emit_cube_txl(ir
, src
);
57 return emit_tex_txs(ir
, src
, {0,1,2,3});
59 return emit_cube_txd(ir
, src
);
61 return emit_cube_lod(ir
, src
);
63 return emit_cube_tg4(ir
, src
);
64 case nir_texop_query_levels
:
65 return emit_tex_txs(ir
, src
, {3,7,7,7});
69 } else if (ir
->sampler_dim
== GLSL_SAMPLER_DIM_BUF
) {
72 return emit_buf_txf(ir
, src
);
74 return emit_tex_txs(ir
, src
, {0,1,2,3});
81 return emit_tex_tex(ir
, src
);
83 return emit_tex_txf(ir
, src
);
85 return emit_tex_txb(ir
, src
);
87 return emit_tex_txl(ir
, src
);
89 return emit_tex_txd(ir
, src
);
91 return emit_tex_txs(ir
, src
, {0,1,2,3});
93 return emit_tex_lod(ir
, src
);
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});
109 bool EmitTexInstruction::emit_cube_txf(UNUSED nir_tex_instr
* instr
, UNUSED TexInputs
&src
)
114 bool EmitTexInstruction::emit_cube_txd(nir_tex_instr
* instr
, TexInputs
& tex_src
)
117 assert(instr
->src
[0].src
.is_ssa
);
119 r600::sfn_log
<< SfnLog::instr
<< "emit '"
120 << *reinterpret_cast<nir_instr
*>(instr
)
121 << "' (" << __func__
<< ")\n";
123 auto tex_op
= TexInstruction::sample_g
;
125 std::array
<PValue
, 4> v
;
126 for (int i
= 0; i
< 4; ++i
)
127 v
[i
] = from_nir(instr
->dest
, i
);
130 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
132 std::array
<PValue
,4> dst_elms
;
133 std::array
<PValue
,4> src_elms
;
135 const uint16_t lookup
[4] = {1, 0, 3, 2};
136 for (uint16_t i
= 0; i
< 4; ++i
) {
138 src_elms
[i
] = cubed
.reg_i(lookup
[i
]);
141 GPRVector
empty_dst(0, {7,7,7,7});
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
;
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
}));
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
}));
160 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
161 assert(!sampler
.indirect
);
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});
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});
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
);
176 set_rect_coordinate_flags(instr
, ir
);
177 //set_offsets(ir, tex_src.offset);
179 emit_instruction(irgh
);
180 emit_instruction(irgv
);
181 emit_instruction(ir
);
186 bool EmitTexInstruction::emit_cube_txl(nir_tex_instr
* instr
, TexInputs
& tex_src
)
188 assert(instr
->src
[0].src
.is_ssa
);
190 if (instr
->is_shadow
)
193 r600::sfn_log
<< SfnLog::instr
<< "emit '"
194 << *reinterpret_cast<nir_instr
*>(instr
)
195 << "' (" << __func__
<< ")\n";
197 std::array
<PValue
, 4> v
;
198 for (int i
= 0; i
< 4; ++i
)
199 v
[i
] = from_nir(instr
->dest
, i
);
202 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
204 std::array
<PValue
,4> dst_elms
;
205 std::array
<PValue
,4> src_elms
;
207 const uint16_t lookup
[4] = {1, 0, 3, 2};
208 for (uint16_t i
= 0; i
< 4; ++i
) {
210 src_elms
[i
] = cubed
.reg_i(lookup
[i
]);
213 auto *ir
= new AluInstruction(op1_mov
, src_elms
[3], tex_src
.lod
,
214 {alu_last_instr
, alu_write
});
215 emit_instruction(ir
);
217 GPRVector
src(src_elms
);
218 GPRVector
dst(dst_elms
);
220 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
221 assert(!sampler
.indirect
);
223 auto tir
= new TexInstruction(TexInstruction::sample_l
, dst
, src
,
224 sampler
.id
,sampler
.id
+ R600_MAX_CONST_BUFFERS
,
225 tex_src
.sampler_offset
);
228 tir
->set_flag(TexInstruction::z_unnormalized
);
230 emit_instruction(tir
);
234 bool EmitTexInstruction::emit_cube_lod(nir_tex_instr
* instr
, TexInputs
& src
)
236 auto tex_op
= TexInstruction::get_tex_lod
;
238 std::array
<PValue
, 4> v
;
239 for (int i
= 0; i
< 4; ++i
)
240 v
[i
] = from_nir(instr
->dest
, i
);
243 emit_cube_prep(src
.coord
, cubed
, instr
->is_array
);
245 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
246 assert(!sampler
.indirect
);
248 auto dst
= make_dest(*instr
);
249 auto irt
= new TexInstruction(tex_op
, dst
, cubed
, sampler
.id
,
250 sampler
.id
+ R600_MAX_CONST_BUFFERS
,
253 emit_instruction(irt
);
259 bool EmitTexInstruction::emit_cube_txb(nir_tex_instr
* instr
, TexInputs
& tex_src
)
261 assert(instr
->src
[0].src
.is_ssa
);
263 r600::sfn_log
<< SfnLog::instr
<< "emit '"
264 << *reinterpret_cast<nir_instr
*>(instr
)
265 << "' (" << __func__
<< ")\n";
267 std::array
<PValue
, 4> v
;
268 for (int i
= 0; i
< 4; ++i
)
269 v
[i
] = from_nir(instr
->dest
, i
);
272 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
274 std::array
<PValue
,4> dst_elms
;
275 std::array
<PValue
,4> src_elms
;
277 const uint16_t lookup
[4] = {1, 0, 3, 2};
278 for (uint16_t i
= 0; i
< 4; ++i
) {
280 src_elms
[i
] = v
[lookup
[i
]];
283 GPRVector
src(src_elms
);
284 GPRVector
dst(dst_elms
);
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
}));
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
;
296 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
297 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
299 auto tir
= new TexInstruction(tex_op
, dst
, src
,
301 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
302 emit_instruction(tir
);
307 bool EmitTexInstruction::emit_cube_tex(nir_tex_instr
* instr
, TexInputs
& tex_src
)
309 std::array
<PValue
, 4> v
;
310 for (int i
= 0; i
< 4; ++i
)
311 v
[i
] = from_nir(instr
->dest
, i
);
313 auto tex_op
= TexInstruction::sample
;
315 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
317 std::array
<PValue
,4> dst_elms
;
318 std::array
<PValue
,4> src_elms
;
320 const uint16_t lookup
[4] = {1, 0, 3, 2};
321 for (uint16_t i
= 0; i
< 4; ++i
) {
323 src_elms
[i
] = v
[lookup
[i
]];
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
;
332 GPRVector
dst(dst_elms
);
333 GPRVector
src(src_elms
);
335 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
336 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
338 auto tir
= new TexInstruction(tex_op
, dst
, src
,
340 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
342 tir
->set_flag(TexInstruction::z_unnormalized
);
344 emit_instruction(tir
);
349 bool EmitTexInstruction::emit_cube_prep(const GPRVector
& coord
, GPRVector
& cubed
, bool is_array
)
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};
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
});
359 emit_instruction(ir
);
361 ir
->set_flag(alu_last_instr
);
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
);
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
);
373 ir
->set_flag(alu_last_instr
);
376 auto face
= cubed
.reg_i(3);
377 PValue array_index
= get_temp_register();
379 ir
= new AluInstruction(op1_rndne
, array_index
, coord
.reg_i(3), {alu_write
, alu_last_instr
});
380 emit_instruction(ir
);
382 ir
= new AluInstruction(op2_max
, array_index
, {array_index
, Value::zero
}, {alu_write
, alu_last_instr
});
383 emit_instruction(ir
);
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
);
393 bool EmitTexInstruction::emit_buf_txf(nir_tex_instr
* instr
, TexInputs
&src
)
395 auto dst
= make_dest(*instr
);
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
);
405 bool EmitTexInstruction::emit_tex_tex(nir_tex_instr
* instr
, TexInputs
& src
)
408 r600::sfn_log
<< SfnLog::instr
<< "emit '"
409 << *reinterpret_cast<nir_instr
*>(instr
)
410 << "' (" << __func__
<< ")\n";
412 auto tex_op
= TexInstruction::sample
;
414 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
415 assert(!sampler
.indirect
);
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
;
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
);
427 handle_array_index(*instr
, src
.coord
, irt
);
429 set_rect_coordinate_flags(instr
, irt
);
430 set_offsets(irt
, src
.offset
);
432 emit_instruction(irt
);
436 bool EmitTexInstruction::emit_tex_txd(nir_tex_instr
* instr
, TexInputs
& src
)
438 r600::sfn_log
<< SfnLog::instr
<< "emit '"
439 << *reinterpret_cast<nir_instr
*>(instr
)
440 << "' (" << __func__
<< ")\n";
442 auto tex_op
= TexInstruction::sample_g
;
443 auto dst
= make_dest(*instr
);
445 GPRVector
empty_dst(0,{7,7,7,7});
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
;
453 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
454 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
456 TexInstruction
*irgh
= new TexInstruction(TexInstruction::set_gradient_h
, empty_dst
, src
.ddx
,
458 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
459 irgh
->set_dest_swizzle({7,7,7,7});
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});
465 TexInstruction
*ir
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
466 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
468 handle_array_index(*instr
, src
.coord
, ir
);
470 set_rect_coordinate_flags(instr
, ir
);
471 set_offsets(ir
, src
.offset
);
473 emit_instruction(irgh
);
474 emit_instruction(irgv
);
475 emit_instruction(ir
);
479 bool EmitTexInstruction::emit_tex_txf(nir_tex_instr
* instr
, TexInputs
& src
)
481 r600::sfn_log
<< SfnLog::instr
<< "emit '"
482 << *reinterpret_cast<nir_instr
*>(instr
)
483 << "' (" << __func__
<< ")\n";
485 auto dst
= make_dest(*instr
);
487 if (*src
.coord
.reg_i(3) != *src
.lod
)
488 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.lod
, {alu_write
, alu_last_instr
}));
490 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
491 assert(!sampler
.indirect
);
493 /* txf doesn't need rounding for the array index, but 1D has the array index
494 * in the z component */
495 if (instr
->is_array
&& instr
->sampler_dim
== GLSL_SAMPLER_DIM_1D
)
496 src
.coord
.set_reg_i(2, src
.coord
.reg_i(1));
498 auto tex_ir
= new TexInstruction(TexInstruction::ld
, dst
, src
.coord
,
500 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
504 assert(src
.offset
->is_ssa
);
505 AluInstruction
*ir
= nullptr;
506 for (unsigned i
= 0; i
< src
.offset
->ssa
->num_components
; ++i
) {
507 ir
= new AluInstruction(op2_add_int
, src
.coord
.reg_i(i
),
508 {src
.coord
.reg_i(i
), from_nir(*src
.offset
, i
, i
)}, {alu_write
});
509 emit_instruction(ir
);
512 ir
->set_flag(alu_last_instr
);
515 emit_instruction(tex_ir
);
519 bool EmitTexInstruction::emit_tex_lod(nir_tex_instr
* instr
, TexInputs
& src
)
521 auto tex_op
= TexInstruction::get_tex_lod
;
523 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
524 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
526 auto dst
= make_dest(*instr
);
527 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
528 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
529 irt
->set_dest_swizzle({1,0,7,7});
530 emit_instruction(irt
);
535 bool EmitTexInstruction::emit_tex_txl(nir_tex_instr
* instr
, TexInputs
& src
)
537 r600::sfn_log
<< SfnLog::instr
<< "emit '"
538 << *reinterpret_cast<nir_instr
*>(instr
)
539 << "' (" << __func__
<< ")\n";
541 auto tex_op
= TexInstruction::sample_l
;
542 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.lod
,
543 {alu_last_instr
, alu_write
}));
545 if (instr
->is_shadow
) {
546 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(2), src
.comperator
,
547 {alu_last_instr
, alu_write
}));
548 tex_op
= TexInstruction::sample_c_l
;
551 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
552 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
554 auto dst
= make_dest(*instr
);
555 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
556 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
559 handle_array_index(*instr
, src
.coord
, irt
);
561 set_rect_coordinate_flags(instr
, irt
);
562 set_offsets(irt
, src
.offset
);
564 emit_instruction(irt
);
568 bool EmitTexInstruction::emit_tex_txb(nir_tex_instr
* instr
, TexInputs
& src
)
570 auto tex_op
= TexInstruction::sample_lb
;
572 std::array
<uint8_t, 4> in_swizzle
= {0,1,2,3};
574 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.bias
,
575 {alu_last_instr
, alu_write
}));
577 if (instr
->is_shadow
) {
578 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(2), src
.comperator
,
579 {alu_last_instr
, alu_write
}));
580 tex_op
= TexInstruction::sample_c_lb
;
583 GPRVector
tex_src(src
.coord
, in_swizzle
);
585 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
586 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
588 auto dst
= make_dest(*instr
);
589 auto irt
= new TexInstruction(tex_op
, dst
, tex_src
, sampler
.id
,
590 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
592 handle_array_index(*instr
, tex_src
, irt
);
594 set_rect_coordinate_flags(instr
, irt
);
595 set_offsets(irt
, src
.offset
);
597 emit_instruction(irt
);
601 bool EmitTexInstruction::emit_tex_txs(nir_tex_instr
* instr
, TexInputs
& tex_src
,
602 const std::array
<int,4>& dest_swz
)
604 std::array
<PValue
,4> dst_elms
;
605 std::array
<PValue
,4> src_elms
;
607 for (uint16_t i
= 0; i
< 4; ++i
) {
608 dst_elms
[i
] = from_nir(instr
->dest
, (i
< instr
->dest
.ssa
.num_components
) ? i
: 7);
611 GPRVector
dst(dst_elms
);
613 if (instr
->sampler_dim
== GLSL_SAMPLER_DIM_BUF
) {
614 emit_instruction(new FetchInstruction(dst
, PValue(new GPRValue(0, 7)),
615 instr
->sampler_index
+ R600_MAX_CONST_BUFFERS
,
618 for (uint16_t i
= 0; i
< 4; ++i
)
619 src_elms
[i
] = tex_src
.lod
;
620 GPRVector
src(src_elms
);
622 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
623 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
625 auto ir
= new TexInstruction(TexInstruction::get_resinfo
, dst
, src
,
627 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
628 ir
->set_dest_swizzle(dest_swz
);
629 emit_instruction(ir
);
636 bool EmitTexInstruction::emit_tex_texture_samples(nir_tex_instr
* instr
, TexInputs
& src
,
637 const std::array
<int, 4> &dest_swz
)
639 GPRVector dest
= vec_from_nir(instr
->dest
, nir_dest_num_components(instr
->dest
));
640 GPRVector help
{0,{4,4,4,4}};
642 auto dyn_offset
= PValue();
643 int res_id
= R600_MAX_CONST_BUFFERS
+ instr
->sampler_index
;
645 auto ir
= new TexInstruction(TexInstruction::get_nsampled
, dest
, help
,
646 0, res_id
, src
.sampler_offset
);
647 ir
->set_dest_swizzle(dest_swz
);
648 emit_instruction(ir
);
652 bool EmitTexInstruction::emit_tex_tg4(nir_tex_instr
* instr
, TexInputs
& src
)
654 r600::sfn_log
<< SfnLog::instr
<< "emit '"
655 << *reinterpret_cast<nir_instr
*>(instr
)
656 << "' (" << __func__
<< ")\n";
658 auto tex_op
= TexInstruction::gather4
;
660 if (instr
->is_shadow
) {
661 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.comperator
,
662 {alu_last_instr
, alu_write
}));
663 tex_op
= TexInstruction::gather4_c
;
666 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
667 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
669 bool literal_offset
= false;
671 literal_offset
= src
.offset
->is_ssa
&& get_literal_register(*src
.offset
);
672 r600::sfn_log
<< SfnLog::tex
<< " really have offsets and they are " <<
673 (literal_offset
? "literal" : "varying") <<
676 if (!literal_offset
) {
677 GPRVector::Swizzle swizzle
= {4,4,4,4};
678 for (unsigned i
= 0; i
< instr
->coord_components
; ++i
)
681 int noffsets
= instr
->coord_components
;
685 auto ofs
= vec_from_nir_with_fetch_constant(*src
.offset
,
686 ( 1 << noffsets
) - 1,
688 GPRVector
dummy(0, {7,7,7,7});
689 tex_op
= (tex_op
== TexInstruction::gather4_c
) ?
690 TexInstruction::gather4_c_o
: TexInstruction::gather4_o
;
692 auto set_ofs
= new TexInstruction(TexInstruction::set_offsets
, dummy
,
694 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
695 set_ofs
->set_dest_swizzle({7,7,7,7});
696 emit_instruction(set_ofs
);
701 /* pre CAYMAN needs swizzle */
702 auto dst
= make_dest(*instr
);
703 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
704 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
706 irt
->set_dest_swizzle({1,2,0,3});
707 irt
->set_gather_comp(instr
->component
);
710 handle_array_index(*instr
, src
.coord
, irt
);
712 if (literal_offset
) {
713 r600::sfn_log
<< SfnLog::tex
<< "emit literal offsets\n";
714 set_offsets(irt
, src
.offset
);
717 set_rect_coordinate_flags(instr
, irt
);
719 emit_instruction(irt
);
723 bool EmitTexInstruction::emit_cube_tg4(nir_tex_instr
* instr
, TexInputs
& tex_src
)
725 std::array
<PValue
, 4> v
;
726 for (int i
= 0; i
< 4; ++i
)
727 v
[i
] = from_nir(instr
->dest
, i
);
729 auto tex_op
= TexInstruction::gather4
;
731 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
733 std::array
<PValue
,4> dst_elms
;
734 std::array
<PValue
,4> src_elms
;
736 const uint16_t lookup
[4] = {1, 0, 3, 2};
737 for (uint16_t i
= 0; i
< 4; ++i
) {
739 src_elms
[i
] = v
[lookup
[i
]];
742 if (instr
->is_shadow
) {
743 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.comperator
,
744 {alu_last_instr
, alu_write
}));
745 tex_op
= TexInstruction::gather4_c
;
748 GPRVector
dst(dst_elms
);
749 GPRVector
src(src_elms
);
751 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
752 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
754 auto tir
= new TexInstruction(tex_op
, dst
, src
, sampler
.id
,
755 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
757 tir
->set_gather_comp(instr
->component
);
759 tir
->set_dest_swizzle({1, 2, 0, 3});
762 tir
->set_flag(TexInstruction::z_unnormalized
);
764 emit_instruction(tir
);
768 bool EmitTexInstruction::emit_tex_txf_ms(nir_tex_instr
* instr
, TexInputs
& src
)
770 assert(instr
->src
[0].src
.is_ssa
);
772 r600::sfn_log
<< SfnLog::instr
<< "emit '"
773 << *reinterpret_cast<nir_instr
*>(instr
)
774 << "' (" << __func__
<< ")\n";
776 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
777 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
779 int sample_id
= allocate_temp_register();
781 GPRVector
sample_id_dest(sample_id
, {0,7,7,7});
782 PValue
help(new GPRValue(sample_id
, 1));
784 /* FIXME: Texture destination registers must be handled differently,
785 * because the swizzle identfies which source componnet has to be written
786 * at a certain position, and the target register is actually different.
787 * At this point we just add a helper register, but for later work (scheduling
788 * and optimization on the r600 IR level, this needs to be implemented
792 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3),
794 {alu_write
, alu_last_instr
}));
796 auto tex_sample_id_ir
= new TexInstruction(TexInstruction::ld
, sample_id_dest
, src
.coord
,
798 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
799 tex_sample_id_ir
->set_flag(TexInstruction::x_unnormalized
);
800 tex_sample_id_ir
->set_flag(TexInstruction::y_unnormalized
);
801 tex_sample_id_ir
->set_flag(TexInstruction::z_unnormalized
);
802 tex_sample_id_ir
->set_flag(TexInstruction::w_unnormalized
);
803 tex_sample_id_ir
->set_inst_mode(1);
805 emit_instruction(tex_sample_id_ir
);
807 emit_instruction(new AluInstruction(op2_mullo_int
, help
,
808 {src
.ms_index
, PValue(new LiteralValue(4))},
809 {alu_write
, alu_last_instr
}));
811 emit_instruction(new AluInstruction(op2_lshr_int
, src
.coord
.reg_i(3),
812 {sample_id_dest
.reg_i(0), help
},
813 {alu_write
, alu_last_instr
}));
815 emit_instruction(new AluInstruction(op2_and_int
, src
.coord
.reg_i(3),
816 {src
.coord
.reg_i(3), PValue(new LiteralValue(15))},
817 {alu_write
, alu_last_instr
}));
819 auto dst
= make_dest(*instr
);
821 /* txf doesn't need rounding for the array index, but 1D has the array index
822 * in the z component */
823 if (instr
->is_array
&& instr
->sampler_dim
== GLSL_SAMPLER_DIM_1D
)
824 src
.coord
.set_reg_i(2, src
.coord
.reg_i(1));
826 auto tex_ir
= new TexInstruction(TexInstruction::ld
, dst
, src
.coord
,
828 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
832 assert(src
.offset
->is_ssa
);
833 AluInstruction
*ir
= nullptr;
834 for (unsigned i
= 0; i
< src
.offset
->ssa
->num_components
; ++i
) {
835 ir
= new AluInstruction(op2_add_int
, src
.coord
.reg_i(i
),
836 {src
.coord
.reg_i(i
), from_nir(*src
.offset
, i
, i
)}, {alu_write
});
837 emit_instruction(ir
);
840 ir
->set_flag(alu_last_instr
);
843 emit_instruction(tex_ir
);
847 bool EmitTexInstruction::get_inputs(const nir_tex_instr
& instr
, TexInputs
&src
)
849 sfn_log
<< SfnLog::tex
<< "Get Inputs with " << instr
.coord_components
<< " components\n";
851 unsigned grad_components
= instr
.coord_components
;
856 src
.offset
= nullptr;
858 for (unsigned i
= 0; i
< instr
.num_srcs
; ++i
) {
859 switch (instr
.src
[i
].src_type
) {
860 case nir_tex_src_bias
:
861 src
.bias
= from_nir(instr
.src
[i
], 0);
864 case nir_tex_src_coord
: {
865 src
.coord
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
866 (1 << instr
.coord_components
) - 1,
869 case nir_tex_src_comparator
:
870 src
.comperator
= from_nir(instr
.src
[i
], 0);
872 case nir_tex_src_ddx
: {
873 sfn_log
<< SfnLog::tex
<< "Get DDX ";
874 src
.ddx
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
875 (1 << grad_components
) - 1,
876 swizzle_from_comps(grad_components
));
877 sfn_log
<< SfnLog::tex
<< src
.ddx
<< "\n";
879 case nir_tex_src_ddy
:{
880 sfn_log
<< SfnLog::tex
<< "Get DDY ";
881 src
.ddy
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
882 (1 << grad_components
) - 1,
883 swizzle_from_comps(grad_components
));
884 sfn_log
<< SfnLog::tex
<< src
.ddy
<< "\n";
886 case nir_tex_src_lod
:
887 src
.lod
= from_nir_with_fetch_constant(instr
.src
[i
].src
, 0);
889 case nir_tex_src_offset
:
890 sfn_log
<< SfnLog::tex
<< " -- Find offset\n";
891 src
.offset
= &instr
.src
[i
].src
;
893 case nir_tex_src_sampler_deref
:
894 src
.sampler_deref
= get_deref_location(instr
.src
[i
].src
);
896 case nir_tex_src_texture_deref
:
897 src
.texture_deref
= get_deref_location(instr
.src
[i
].src
);
899 case nir_tex_src_ms_index
:
900 src
.ms_index
= from_nir(instr
.src
[i
], 0);
902 case nir_tex_src_texture_offset
:
903 src
.texture_offset
= from_nir(instr
.src
[i
], 0);
905 case nir_tex_src_sampler_offset
:
906 src
.sampler_offset
= from_nir(instr
.src
[i
], 0);
908 case nir_tex_src_plane
:
909 case nir_tex_src_projector
:
910 case nir_tex_src_min_lod
:
911 case nir_tex_src_ms_mcs
:
913 sfn_log
<< SfnLog::tex
<< "Texture source type " << instr
.src
[i
].src_type
<< " not supported\n";
920 GPRVector
EmitTexInstruction::make_dest(nir_tex_instr
& instr
)
922 int num_dest_components
= instr
.dest
.is_ssa
? instr
.dest
.ssa
.num_components
:
923 instr
.dest
.reg
.reg
->num_components
;
924 std::array
<PValue
,4> dst_elms
;
925 for (uint16_t i
= 0; i
< 4; ++i
)
926 dst_elms
[i
] = from_nir(instr
.dest
, (i
< num_dest_components
) ? i
: 7);
927 return GPRVector(dst_elms
);
931 GPRVector
EmitTexInstruction::make_dest(nir_tex_instr
& instr
,
932 const std::array
<int, 4>& swizzle
)
934 int num_dest_components
= instr
.dest
.is_ssa
? instr
.dest
.ssa
.num_components
:
935 instr
.dest
.reg
.reg
->num_components
;
936 std::array
<PValue
,4> dst_elms
;
937 for (uint16_t i
= 0; i
< 4; ++i
) {
939 dst_elms
[i
] = from_nir(instr
.dest
, (k
< num_dest_components
) ? k
: 7);
941 return GPRVector(dst_elms
);
944 void EmitTexInstruction::set_rect_coordinate_flags(nir_tex_instr
* instr
,
945 TexInstruction
* ir
) const
947 if (instr
->sampler_dim
== GLSL_SAMPLER_DIM_RECT
) {
948 ir
->set_flag(TexInstruction::x_unnormalized
);
949 ir
->set_flag(TexInstruction::y_unnormalized
);
953 void EmitTexInstruction::set_offsets(TexInstruction
* ir
, nir_src
*offset
)
958 assert(offset
->is_ssa
);
959 auto literal
= get_literal_register(*offset
);
962 for (int i
= 0; i
< offset
->ssa
->num_components
; ++i
) {
963 ir
->set_offset(i
, literal
->value
[i
].i32
);
967 void EmitTexInstruction::handle_array_index(const nir_tex_instr
& instr
, const GPRVector
& src
, TexInstruction
*ir
)
969 int src_idx
= instr
.sampler_dim
== GLSL_SAMPLER_DIM_1D
? 1 : 2;
970 emit_instruction(new AluInstruction(op1_rndne
, src
.reg_i(2), src
.reg_i(src_idx
),
971 {alu_last_instr
, alu_write
}));
972 ir
->set_flag(TexInstruction::z_unnormalized
);
975 EmitTexInstruction::SamplerId
976 EmitTexInstruction::get_samplerr_id(int sampler_id
, const nir_variable
*deref
)
978 EmitTexInstruction::SamplerId result
= {sampler_id
, false};
981 assert(glsl_type_is_sampler(deref
->type
));
982 result
.id
= deref
->data
.binding
;
987 EmitTexInstruction::TexInputs::TexInputs():
988 sampler_deref(nullptr),
989 texture_deref(nullptr),