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});
106 bool EmitTexInstruction::emit_cube_txf(UNUSED nir_tex_instr
* instr
, UNUSED TexInputs
&src
)
111 bool EmitTexInstruction::emit_cube_txd(nir_tex_instr
* instr
, TexInputs
& tex_src
)
114 assert(instr
->src
[0].src
.is_ssa
);
116 r600::sfn_log
<< SfnLog::instr
<< "emit '"
117 << *reinterpret_cast<nir_instr
*>(instr
)
118 << "' (" << __func__
<< ")\n";
120 auto tex_op
= TexInstruction::sample_g
;
122 std::array
<PValue
, 4> v
;
123 for (int i
= 0; i
< 4; ++i
)
124 v
[i
] = from_nir(instr
->dest
, i
);
127 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
129 std::array
<PValue
,4> dst_elms
;
130 std::array
<PValue
,4> src_elms
;
132 const uint16_t lookup
[4] = {1, 0, 3, 2};
133 for (uint16_t i
= 0; i
< 4; ++i
) {
135 src_elms
[i
] = cubed
.reg_i(lookup
[i
]);
138 GPRVector
empty_dst(0, {7,7,7,7});
140 if (instr
->is_shadow
) {
141 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.comperator
,
142 {alu_last_instr
, alu_write
}));
143 tex_op
= TexInstruction::sample_c_g
;
147 PValue
half(new LiteralValue(0.5f
));
148 for (int i
= 0; i
< 3; ++i
) {
149 emit_instruction(new AluInstruction(op2_mul_ieee
, tex_src
.ddx
.reg_i(i
), {tex_src
.ddx
.reg_i(i
), half
},
150 {alu_last_instr
, alu_write
}));
152 for (int i
= 0; i
< 3; ++i
) {
153 emit_instruction(new AluInstruction(op2_mul_ieee
, tex_src
.ddy
.reg_i(i
), {tex_src
.ddy
.reg_i(i
), half
},
154 {alu_last_instr
, alu_write
}));
157 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
158 assert(!sampler
.indirect
);
160 TexInstruction
*irgh
= new TexInstruction(TexInstruction::set_gradient_h
, empty_dst
, tex_src
.ddx
,
161 sampler
.id
, sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
162 irgh
->set_dest_swizzle({7,7,7,7});
164 TexInstruction
*irgv
= new TexInstruction(TexInstruction::set_gradient_v
, empty_dst
, tex_src
.ddy
,
165 sampler
.id
, sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
166 irgv
->set_dest_swizzle({7,7,7,7});
168 GPRVector
dst(dst_elms
);
169 GPRVector
src(src_elms
);
170 TexInstruction
*ir
= new TexInstruction(tex_op
, dst
, src
, instr
->sampler_index
,
171 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
173 set_rect_coordinate_flags(instr
, ir
);
174 //set_offsets(ir, tex_src.offset);
176 emit_instruction(irgh
);
177 emit_instruction(irgv
);
178 emit_instruction(ir
);
183 bool EmitTexInstruction::emit_cube_txl(nir_tex_instr
* instr
, TexInputs
& tex_src
)
185 assert(instr
->src
[0].src
.is_ssa
);
187 if (instr
->is_shadow
)
190 r600::sfn_log
<< SfnLog::instr
<< "emit '"
191 << *reinterpret_cast<nir_instr
*>(instr
)
192 << "' (" << __func__
<< ")\n";
194 std::array
<PValue
, 4> v
;
195 for (int i
= 0; i
< 4; ++i
)
196 v
[i
] = from_nir(instr
->dest
, i
);
199 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
201 std::array
<PValue
,4> dst_elms
;
202 std::array
<PValue
,4> src_elms
;
204 const uint16_t lookup
[4] = {1, 0, 3, 2};
205 for (uint16_t i
= 0; i
< 4; ++i
) {
207 src_elms
[i
] = cubed
.reg_i(lookup
[i
]);
210 auto *ir
= new AluInstruction(op1_mov
, src_elms
[3], tex_src
.lod
,
211 {alu_last_instr
, alu_write
});
212 emit_instruction(ir
);
214 GPRVector
src(src_elms
);
215 GPRVector
dst(dst_elms
);
217 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
218 assert(!sampler
.indirect
);
220 auto tir
= new TexInstruction(TexInstruction::sample_l
, dst
, src
,
221 sampler
.id
,sampler
.id
+ R600_MAX_CONST_BUFFERS
,
222 tex_src
.sampler_offset
);
225 tir
->set_flag(TexInstruction::z_unnormalized
);
227 emit_instruction(tir
);
231 bool EmitTexInstruction::emit_cube_lod(nir_tex_instr
* instr
, TexInputs
& src
)
233 auto tex_op
= TexInstruction::get_tex_lod
;
235 std::array
<PValue
, 4> v
;
236 for (int i
= 0; i
< 4; ++i
)
237 v
[i
] = from_nir(instr
->dest
, i
);
240 emit_cube_prep(src
.coord
, cubed
, instr
->is_array
);
242 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
243 assert(!sampler
.indirect
);
245 auto dst
= make_dest(*instr
);
246 auto irt
= new TexInstruction(tex_op
, dst
, cubed
, sampler
.id
,
247 sampler
.id
+ R600_MAX_CONST_BUFFERS
,
250 emit_instruction(irt
);
256 bool EmitTexInstruction::emit_cube_txb(nir_tex_instr
* instr
, TexInputs
& tex_src
)
258 assert(instr
->src
[0].src
.is_ssa
);
260 r600::sfn_log
<< SfnLog::instr
<< "emit '"
261 << *reinterpret_cast<nir_instr
*>(instr
)
262 << "' (" << __func__
<< ")\n";
264 std::array
<PValue
, 4> v
;
265 for (int i
= 0; i
< 4; ++i
)
266 v
[i
] = from_nir(instr
->dest
, i
);
269 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
271 std::array
<PValue
,4> dst_elms
;
272 std::array
<PValue
,4> src_elms
;
274 const uint16_t lookup
[4] = {1, 0, 3, 2};
275 for (uint16_t i
= 0; i
< 4; ++i
) {
277 src_elms
[i
] = v
[lookup
[i
]];
280 GPRVector
src(src_elms
);
281 GPRVector
dst(dst_elms
);
283 auto tex_op
= TexInstruction::sample_lb
;
284 if (!instr
->is_shadow
) {
285 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.bias
,
286 {alu_last_instr
, alu_write
}));
288 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.comperator
,
289 {alu_last_instr
, alu_write
}));
290 tex_op
= TexInstruction::sample_c_lb
;
293 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
294 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
296 auto tir
= new TexInstruction(tex_op
, dst
, src
,
298 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
299 emit_instruction(tir
);
304 bool EmitTexInstruction::emit_cube_tex(nir_tex_instr
* instr
, TexInputs
& tex_src
)
306 std::array
<PValue
, 4> v
;
307 for (int i
= 0; i
< 4; ++i
)
308 v
[i
] = from_nir(instr
->dest
, i
);
310 auto tex_op
= TexInstruction::sample
;
312 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
314 std::array
<PValue
,4> dst_elms
;
315 std::array
<PValue
,4> src_elms
;
317 const uint16_t lookup
[4] = {1, 0, 3, 2};
318 for (uint16_t i
= 0; i
< 4; ++i
) {
320 src_elms
[i
] = v
[lookup
[i
]];
323 if (instr
->is_shadow
) {
324 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.comperator
,
325 {alu_last_instr
, alu_write
}));
326 tex_op
= TexInstruction::sample_c
;
329 GPRVector
dst(dst_elms
);
330 GPRVector
src(src_elms
);
332 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
333 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
335 auto tir
= new TexInstruction(tex_op
, dst
, src
,
337 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
339 tir
->set_flag(TexInstruction::z_unnormalized
);
341 emit_instruction(tir
);
346 bool EmitTexInstruction::emit_cube_prep(const GPRVector
& coord
, GPRVector
& cubed
, bool is_array
)
348 AluInstruction
*ir
= nullptr;
349 const uint16_t src0_chan
[4] = {2, 2, 0, 1};
350 const uint16_t src1_chan
[4] = {1, 0, 2, 2};
352 for (int i
= 0; i
< 4; ++i
) {
353 ir
= new AluInstruction(op2_cube
, cubed
.reg_i(i
), coord
.reg_i(src0_chan
[i
]),
354 coord
.reg_i(src1_chan
[i
]), {alu_write
});
356 emit_instruction(ir
);
358 ir
->set_flag(alu_last_instr
);
360 ir
= new AluInstruction(op1_recip_ieee
, cubed
.reg_i(2), cubed
.reg_i(2), {alu_write
, alu_last_instr
});
361 ir
->set_flag(alu_src0_abs
);
362 emit_instruction(ir
);
364 PValue
one_p_5(new LiteralValue(1.5f
));
365 for (int i
= 0; i
< 2; ++i
) {
366 ir
= new AluInstruction(op3_muladd
, cubed
.reg_i(i
), cubed
.reg_i(i
), cubed
.reg_i(2),
367 one_p_5
, {alu_write
});
368 emit_instruction(ir
);
370 ir
->set_flag(alu_last_instr
);
373 auto face
= cubed
.reg_i(3);
374 PValue array_index
= get_temp_register();
376 ir
= new AluInstruction(op1_rndne
, array_index
, coord
.reg_i(3), {alu_write
, alu_last_instr
});
377 emit_instruction(ir
);
379 ir
= new AluInstruction(op2_max
, array_index
, {array_index
, Value::zero
}, {alu_write
, alu_last_instr
});
380 emit_instruction(ir
);
382 ir
= new AluInstruction(op3_muladd
, face
, {array_index
, PValue (new LiteralValue(8.0f
)), face
},
383 {alu_write
, alu_last_instr
});
384 emit_instruction(ir
);
390 bool EmitTexInstruction::emit_buf_txf(nir_tex_instr
* instr
, TexInputs
&src
)
392 auto dst
= make_dest(*instr
);
394 auto ir
= new FetchInstruction(vc_fetch
, no_index_offset
, dst
, src
.coord
.reg_i(0), 0,
395 instr
->texture_index
+ R600_MAX_CONST_BUFFERS
,
397 ir
->set_flag(vtx_use_const_field
);
398 emit_instruction(ir
);
402 bool EmitTexInstruction::emit_tex_tex(nir_tex_instr
* instr
, TexInputs
& src
)
405 r600::sfn_log
<< SfnLog::instr
<< "emit '"
406 << *reinterpret_cast<nir_instr
*>(instr
)
407 << "' (" << __func__
<< ")\n";
409 auto tex_op
= TexInstruction::sample
;
411 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
412 assert(!sampler
.indirect
);
414 if (instr
->is_shadow
) {
415 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.comperator
,
416 {alu_last_instr
, alu_write
}));
417 tex_op
= TexInstruction::sample_c
;
420 auto dst
= make_dest(*instr
);
421 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
422 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
424 handle_array_index(*instr
, src
.coord
, irt
);
426 set_rect_coordinate_flags(instr
, irt
);
427 set_offsets(irt
, src
.offset
);
429 emit_instruction(irt
);
433 bool EmitTexInstruction::emit_tex_txd(nir_tex_instr
* instr
, TexInputs
& src
)
435 r600::sfn_log
<< SfnLog::instr
<< "emit '"
436 << *reinterpret_cast<nir_instr
*>(instr
)
437 << "' (" << __func__
<< ")\n";
439 auto tex_op
= TexInstruction::sample_g
;
440 auto dst
= make_dest(*instr
);
442 GPRVector
empty_dst(0,{7,7,7,7});
444 if (instr
->is_shadow
) {
445 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.comperator
,
446 {alu_last_instr
, alu_write
}));
447 tex_op
= TexInstruction::sample_c_g
;
450 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
451 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
453 TexInstruction
*irgh
= new TexInstruction(TexInstruction::set_gradient_h
, empty_dst
, src
.ddx
,
455 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
456 irgh
->set_dest_swizzle({7,7,7,7});
458 TexInstruction
*irgv
= new TexInstruction(TexInstruction::set_gradient_v
, empty_dst
, src
.ddy
,
459 sampler
.id
, sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
460 irgv
->set_dest_swizzle({7,7,7,7});
462 TexInstruction
*ir
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
463 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
465 handle_array_index(*instr
, src
.coord
, ir
);
467 set_rect_coordinate_flags(instr
, ir
);
468 set_offsets(ir
, src
.offset
);
470 emit_instruction(irgh
);
471 emit_instruction(irgv
);
472 emit_instruction(ir
);
476 bool EmitTexInstruction::emit_tex_txf(nir_tex_instr
* instr
, TexInputs
& src
)
478 r600::sfn_log
<< SfnLog::instr
<< "emit '"
479 << *reinterpret_cast<nir_instr
*>(instr
)
480 << "' (" << __func__
<< ")\n";
482 auto dst
= make_dest(*instr
);
484 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.lod
, {alu_write
, alu_last_instr
}));
486 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
487 assert(!sampler
.indirect
);
489 /* txf doesn't need rounding for the array index, but 1D has the array index
490 * in the z component */
491 if (instr
->is_array
&& instr
->sampler_dim
== GLSL_SAMPLER_DIM_1D
)
492 src
.coord
.set_reg_i(2, src
.coord
.reg_i(1));
494 auto tex_ir
= new TexInstruction(TexInstruction::ld
, dst
, src
.coord
,
496 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
500 assert(src
.offset
->is_ssa
);
501 AluInstruction
*ir
= nullptr;
502 for (unsigned i
= 0; i
< src
.offset
->ssa
->num_components
; ++i
) {
503 ir
= new AluInstruction(op2_add_int
, src
.coord
.reg_i(i
),
504 {src
.coord
.reg_i(i
), from_nir(*src
.offset
, i
, i
)}, {alu_write
});
505 emit_instruction(ir
);
508 ir
->set_flag(alu_last_instr
);
511 emit_instruction(tex_ir
);
515 bool EmitTexInstruction::emit_tex_lod(nir_tex_instr
* instr
, TexInputs
& src
)
517 auto tex_op
= TexInstruction::get_tex_lod
;
519 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
520 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
522 auto dst
= make_dest(*instr
);
523 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
524 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
525 irt
->set_dest_swizzle({1,0,7,7});
526 emit_instruction(irt
);
531 bool EmitTexInstruction::emit_tex_txl(nir_tex_instr
* instr
, TexInputs
& src
)
533 r600::sfn_log
<< SfnLog::instr
<< "emit '"
534 << *reinterpret_cast<nir_instr
*>(instr
)
535 << "' (" << __func__
<< ")\n";
537 auto tex_op
= TexInstruction::sample_l
;
538 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.lod
,
539 {alu_last_instr
, alu_write
}));
541 if (instr
->is_shadow
) {
542 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(2), src
.comperator
,
543 {alu_last_instr
, alu_write
}));
544 tex_op
= TexInstruction::sample_c_l
;
547 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
548 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
550 auto dst
= make_dest(*instr
);
551 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
552 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
555 handle_array_index(*instr
, src
.coord
, irt
);
557 set_rect_coordinate_flags(instr
, irt
);
558 set_offsets(irt
, src
.offset
);
560 emit_instruction(irt
);
564 bool EmitTexInstruction::emit_tex_txb(nir_tex_instr
* instr
, TexInputs
& src
)
566 auto tex_op
= TexInstruction::sample_lb
;
568 std::array
<uint8_t, 4> in_swizzle
= {0,1,2,3};
570 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.bias
,
571 {alu_last_instr
, alu_write
}));
573 if (instr
->is_shadow
) {
574 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(2), src
.comperator
,
575 {alu_last_instr
, alu_write
}));
576 tex_op
= TexInstruction::sample_c_lb
;
579 GPRVector
tex_src(src
.coord
, in_swizzle
);
581 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
582 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
584 auto dst
= make_dest(*instr
);
585 auto irt
= new TexInstruction(tex_op
, dst
, tex_src
, sampler
.id
,
586 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
588 handle_array_index(*instr
, tex_src
, irt
);
590 set_rect_coordinate_flags(instr
, irt
);
591 set_offsets(irt
, src
.offset
);
593 emit_instruction(irt
);
597 bool EmitTexInstruction::emit_tex_txs(nir_tex_instr
* instr
, TexInputs
& tex_src
,
598 const std::array
<int,4>& dest_swz
)
600 std::array
<PValue
,4> dst_elms
;
601 std::array
<PValue
,4> src_elms
;
603 for (uint16_t i
= 0; i
< 4; ++i
) {
604 dst_elms
[i
] = from_nir(instr
->dest
, (i
< instr
->dest
.ssa
.num_components
) ? i
: 7);
607 GPRVector
dst(dst_elms
);
609 if (instr
->sampler_dim
== GLSL_SAMPLER_DIM_BUF
) {
610 emit_instruction(new FetchInstruction(dst
, PValue(new GPRValue(0, 7)),
611 instr
->sampler_index
+ R600_MAX_CONST_BUFFERS
,
614 for (uint16_t i
= 0; i
< 4; ++i
)
615 src_elms
[i
] = tex_src
.lod
;
616 GPRVector
src(src_elms
);
618 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
619 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
621 auto ir
= new TexInstruction(TexInstruction::get_resinfo
, dst
, src
,
623 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
624 ir
->set_dest_swizzle(dest_swz
);
625 emit_instruction(ir
);
632 bool EmitTexInstruction::emit_tex_tg4(nir_tex_instr
* instr
, TexInputs
& src
)
634 r600::sfn_log
<< SfnLog::instr
<< "emit '"
635 << *reinterpret_cast<nir_instr
*>(instr
)
636 << "' (" << __func__
<< ")\n";
638 auto tex_op
= TexInstruction::gather4
;
640 if (instr
->is_shadow
) {
641 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3), src
.comperator
,
642 {alu_last_instr
, alu_write
}));
643 tex_op
= TexInstruction::gather4_c
;
646 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
647 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
649 bool literal_offset
= false;
651 literal_offset
= src
.offset
->is_ssa
&& get_literal_register(*src
.offset
);
652 r600::sfn_log
<< SfnLog::tex
<< " really have offsets and they are " <<
653 (literal_offset
? "literal" : "varying") <<
656 if (!literal_offset
) {
657 GPRVector::Swizzle swizzle
= {4,4,4,4};
658 for (unsigned i
= 0; i
< instr
->coord_components
; ++i
)
661 int noffsets
= instr
->coord_components
;
665 auto ofs
= vec_from_nir_with_fetch_constant(*src
.offset
,
666 ( 1 << noffsets
) - 1,
668 GPRVector
dummy(0, {7,7,7,7});
669 tex_op
= (tex_op
== TexInstruction::gather4_c
) ?
670 TexInstruction::gather4_c_o
: TexInstruction::gather4_o
;
672 auto set_ofs
= new TexInstruction(TexInstruction::set_offsets
, dummy
,
674 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
675 set_ofs
->set_dest_swizzle({7,7,7,7});
676 emit_instruction(set_ofs
);
681 /* pre CAYMAN needs swizzle */
682 auto dst
= make_dest(*instr
);
683 auto irt
= new TexInstruction(tex_op
, dst
, src
.coord
, sampler
.id
,
684 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
686 irt
->set_dest_swizzle({1,2,0,3});
687 irt
->set_gather_comp(instr
->component
);
690 handle_array_index(*instr
, src
.coord
, irt
);
692 if (literal_offset
) {
693 r600::sfn_log
<< SfnLog::tex
<< "emit literal offsets\n";
694 set_offsets(irt
, src
.offset
);
697 set_rect_coordinate_flags(instr
, irt
);
699 emit_instruction(irt
);
703 bool EmitTexInstruction::emit_cube_tg4(nir_tex_instr
* instr
, TexInputs
& tex_src
)
705 std::array
<PValue
, 4> v
;
706 for (int i
= 0; i
< 4; ++i
)
707 v
[i
] = from_nir(instr
->dest
, i
);
709 auto tex_op
= TexInstruction::gather4
;
711 emit_cube_prep(tex_src
.coord
, cubed
, instr
->is_array
);
713 std::array
<PValue
,4> dst_elms
;
714 std::array
<PValue
,4> src_elms
;
716 const uint16_t lookup
[4] = {1, 0, 3, 2};
717 for (uint16_t i
= 0; i
< 4; ++i
) {
719 src_elms
[i
] = v
[lookup
[i
]];
722 if (instr
->is_shadow
) {
723 emit_instruction(new AluInstruction(op1_mov
, src_elms
[3], tex_src
.comperator
,
724 {alu_last_instr
, alu_write
}));
725 tex_op
= TexInstruction::gather4_c
;
728 GPRVector
dst(dst_elms
);
729 GPRVector
src(src_elms
);
731 auto sampler
= get_samplerr_id(instr
->sampler_index
, tex_src
.sampler_deref
);
732 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
734 auto tir
= new TexInstruction(tex_op
, dst
, src
, sampler
.id
,
735 sampler
.id
+ R600_MAX_CONST_BUFFERS
, tex_src
.sampler_offset
);
737 tir
->set_gather_comp(instr
->component
);
739 tir
->set_dest_swizzle({1, 2, 0, 3});
742 tir
->set_flag(TexInstruction::z_unnormalized
);
744 emit_instruction(tir
);
748 bool EmitTexInstruction::emit_tex_txf_ms(nir_tex_instr
* instr
, TexInputs
& src
)
750 assert(instr
->src
[0].src
.is_ssa
);
752 r600::sfn_log
<< SfnLog::instr
<< "emit '"
753 << *reinterpret_cast<nir_instr
*>(instr
)
754 << "' (" << __func__
<< ")\n";
756 auto sampler
= get_samplerr_id(instr
->sampler_index
, src
.sampler_deref
);
757 assert(!sampler
.indirect
&& "Indirect sampler selection not yet supported");
759 int sample_id
= allocate_temp_register();
761 GPRVector
sample_id_dest(sample_id
, {0,7,7,7});
762 PValue
help(new GPRValue(sample_id
, 1));
764 /* FIXME: Texture destination registers must be handled differently,
765 * because the swizzle identfies which source componnet has to be written
766 * at a certain position, and the target register is actually different.
767 * At this point we just add a helper register, but for later work (scheduling
768 * and optimization on the r600 IR level, this needs to be implemented
772 emit_instruction(new AluInstruction(op1_mov
, src
.coord
.reg_i(3),
774 {alu_write
, alu_last_instr
}));
776 auto tex_sample_id_ir
= new TexInstruction(TexInstruction::ld
, sample_id_dest
, src
.coord
,
778 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
779 tex_sample_id_ir
->set_flag(TexInstruction::x_unnormalized
);
780 tex_sample_id_ir
->set_flag(TexInstruction::y_unnormalized
);
781 tex_sample_id_ir
->set_flag(TexInstruction::z_unnormalized
);
782 tex_sample_id_ir
->set_flag(TexInstruction::w_unnormalized
);
783 tex_sample_id_ir
->set_inst_mode(1);
785 emit_instruction(tex_sample_id_ir
);
787 emit_instruction(new AluInstruction(op2_mullo_int
, help
,
788 {src
.ms_index
, PValue(new LiteralValue(4))},
789 {alu_write
, alu_last_instr
}));
791 emit_instruction(new AluInstruction(op2_lshr_int
, src
.coord
.reg_i(3),
792 {sample_id_dest
.reg_i(0), help
},
793 {alu_write
, alu_last_instr
}));
795 emit_instruction(new AluInstruction(op2_and_int
, src
.coord
.reg_i(3),
796 {src
.coord
.reg_i(3), PValue(new LiteralValue(15))},
797 {alu_write
, alu_last_instr
}));
799 auto dst
= make_dest(*instr
);
801 /* txf doesn't need rounding for the array index, but 1D has the array index
802 * in the z component */
803 if (instr
->is_array
&& instr
->sampler_dim
== GLSL_SAMPLER_DIM_1D
)
804 src
.coord
.set_reg_i(2, src
.coord
.reg_i(1));
806 auto tex_ir
= new TexInstruction(TexInstruction::ld
, dst
, src
.coord
,
808 sampler
.id
+ R600_MAX_CONST_BUFFERS
, src
.sampler_offset
);
812 assert(src
.offset
->is_ssa
);
813 AluInstruction
*ir
= nullptr;
814 for (unsigned i
= 0; i
< src
.offset
->ssa
->num_components
; ++i
) {
815 ir
= new AluInstruction(op2_add_int
, src
.coord
.reg_i(i
),
816 {src
.coord
.reg_i(i
), from_nir(*src
.offset
, i
, i
)}, {alu_write
});
817 emit_instruction(ir
);
820 ir
->set_flag(alu_last_instr
);
823 emit_instruction(tex_ir
);
827 bool EmitTexInstruction::get_inputs(const nir_tex_instr
& instr
, TexInputs
&src
)
829 sfn_log
<< SfnLog::tex
<< "Get Inputs with " << instr
.coord_components
<< " components\n";
831 unsigned grad_components
= instr
.coord_components
;
836 src
.offset
= nullptr;
838 for (unsigned i
= 0; i
< instr
.num_srcs
; ++i
) {
839 switch (instr
.src
[i
].src_type
) {
840 case nir_tex_src_bias
:
841 src
.bias
= from_nir(instr
.src
[i
], 0);
844 case nir_tex_src_coord
: {
845 src
.coord
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
846 (1 << instr
.coord_components
) - 1,
849 case nir_tex_src_comparator
:
850 src
.comperator
= from_nir(instr
.src
[i
], 0);
852 case nir_tex_src_ddx
: {
853 sfn_log
<< SfnLog::tex
<< "Get DDX ";
854 src
.ddx
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
855 (1 << grad_components
) - 1,
856 swizzle_from_comps(grad_components
));
857 sfn_log
<< SfnLog::tex
<< src
.ddx
<< "\n";
859 case nir_tex_src_ddy
:{
860 sfn_log
<< SfnLog::tex
<< "Get DDY ";
861 src
.ddy
= vec_from_nir_with_fetch_constant(instr
.src
[i
].src
,
862 (1 << grad_components
) - 1,
863 swizzle_from_comps(grad_components
));
864 sfn_log
<< SfnLog::tex
<< src
.ddy
<< "\n";
866 case nir_tex_src_lod
:
867 src
.lod
= from_nir_with_fetch_constant(instr
.src
[i
].src
, 0);
869 case nir_tex_src_offset
:
870 sfn_log
<< SfnLog::tex
<< " -- Find offset\n";
871 src
.offset
= &instr
.src
[i
].src
;
873 case nir_tex_src_sampler_deref
:
874 src
.sampler_deref
= get_deref_location(instr
.src
[i
].src
);
876 case nir_tex_src_texture_deref
:
877 src
.texture_deref
= get_deref_location(instr
.src
[i
].src
);
879 case nir_tex_src_ms_index
:
880 src
.ms_index
= from_nir(instr
.src
[i
], 0);
882 case nir_tex_src_texture_offset
:
883 src
.texture_offset
= from_nir(instr
.src
[i
], 0);
885 case nir_tex_src_sampler_offset
:
886 src
.sampler_offset
= from_nir(instr
.src
[i
], 0);
888 case nir_tex_src_plane
:
889 case nir_tex_src_projector
:
890 case nir_tex_src_min_lod
:
891 case nir_tex_src_ms_mcs
:
893 sfn_log
<< SfnLog::tex
<< "Texture source type " << instr
.src
[i
].src_type
<< " not supported\n";
900 GPRVector
EmitTexInstruction::make_dest(nir_tex_instr
& instr
)
902 int num_dest_components
= instr
.dest
.is_ssa
? instr
.dest
.ssa
.num_components
:
903 instr
.dest
.reg
.reg
->num_components
;
904 std::array
<PValue
,4> dst_elms
;
905 for (uint16_t i
= 0; i
< 4; ++i
)
906 dst_elms
[i
] = from_nir(instr
.dest
, (i
< num_dest_components
) ? i
: 7);
907 return GPRVector(dst_elms
);
911 GPRVector
EmitTexInstruction::make_dest(nir_tex_instr
& instr
,
912 const std::array
<int, 4>& swizzle
)
914 int num_dest_components
= instr
.dest
.is_ssa
? instr
.dest
.ssa
.num_components
:
915 instr
.dest
.reg
.reg
->num_components
;
916 std::array
<PValue
,4> dst_elms
;
917 for (uint16_t i
= 0; i
< 4; ++i
) {
919 dst_elms
[i
] = from_nir(instr
.dest
, (k
< num_dest_components
) ? k
: 7);
921 return GPRVector(dst_elms
);
924 void EmitTexInstruction::set_rect_coordinate_flags(nir_tex_instr
* instr
,
925 TexInstruction
* ir
) const
927 if (instr
->sampler_dim
== GLSL_SAMPLER_DIM_RECT
) {
928 ir
->set_flag(TexInstruction::x_unnormalized
);
929 ir
->set_flag(TexInstruction::y_unnormalized
);
933 void EmitTexInstruction::set_offsets(TexInstruction
* ir
, nir_src
*offset
)
938 assert(offset
->is_ssa
);
939 auto literal
= get_literal_register(*offset
);
942 for (int i
= 0; i
< offset
->ssa
->num_components
; ++i
) {
943 ir
->set_offset(i
, literal
->value
[i
].i32
);
947 void EmitTexInstruction::handle_array_index(const nir_tex_instr
& instr
, const GPRVector
& src
, TexInstruction
*ir
)
949 int src_idx
= instr
.sampler_dim
== GLSL_SAMPLER_DIM_1D
? 1 : 2;
950 emit_instruction(new AluInstruction(op1_rndne
, src
.reg_i(2), src
.reg_i(src_idx
),
951 {alu_last_instr
, alu_write
}));
952 ir
->set_flag(TexInstruction::z_unnormalized
);
955 EmitTexInstruction::SamplerId
956 EmitTexInstruction::get_samplerr_id(int sampler_id
, const nir_variable
*deref
)
958 EmitTexInstruction::SamplerId result
= {sampler_id
, false};
961 assert(glsl_type_is_sampler(deref
->type
));
962 result
.id
= deref
->data
.binding
;
967 EmitTexInstruction::TexInputs::TexInputs():
968 sampler_deref(nullptr),
969 texture_deref(nullptr),