aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp
diff options
context:
space:
mode:
authorGert Wollny <[email protected]>2019-12-01 20:38:07 +0100
committerMarge Bot <[email protected]>2020-02-10 19:09:08 +0000
commitf718ac62688b555a933c7112f656944288d04edb (patch)
tree618add486794d43e1efe04e8668e4196e5e9c1ef /src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp
parent295be0e8dfcc28366bcd193c44abc7913d5132d8 (diff)
r600/sfn: Add a basic nir shader backend
This commit adds support for vertex and fragment shaders from NIR, and support for most TEX and ALU instructions. Thanks Dave Airlied for adding support for a number of ALU instructions. v2: fix compilation with gcc-6 v3: rebase: use mesa/core glsl_type_size function Signed-off-by: Gert Wollny <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3225>
Diffstat (limited to 'src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp')
-rw-r--r--src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp974
1 files changed, 974 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp b/src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp
new file mode 100644
index 00000000000..4e43becc8be
--- /dev/null
+++ b/src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp
@@ -0,0 +1,974 @@
+/* -*- mesa-c++ -*-
+ *
+ * Copyright (c) 2018 Collabora LTD
+ *
+ * Author: Gert Wollny <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sfn_emittexinstruction.h"
+#include "sfn_shader_base.h"
+#include "sfn_instruction_fetch.h"
+
+namespace r600 {
+
+EmitTexInstruction::EmitTexInstruction(ShaderFromNirProcessor &processor):
+ EmitInstruction (processor)
+{
+}
+
+bool EmitTexInstruction::do_emit(nir_instr* instr)
+{
+ nir_tex_instr* ir = nir_instr_as_tex(instr);
+
+ TexInputs src;
+ if (!get_inputs(*ir, src))
+ return false;
+
+ if (ir->sampler_dim == GLSL_SAMPLER_DIM_CUBE) {
+ switch (ir->op) {
+ case nir_texop_tex:
+ return emit_cube_tex(ir, src);
+ case nir_texop_txf:
+ return emit_cube_txf(ir, src);
+ case nir_texop_txb:
+ return emit_cube_txb(ir, src);
+ case nir_texop_txl:
+ return emit_cube_txl(ir, src);
+ case nir_texop_txs:
+ return emit_tex_txs(ir, src, {0,1,2,3});
+ case nir_texop_txd:
+ return emit_cube_txd(ir, src);
+ case nir_texop_lod:
+ return emit_cube_lod(ir, src);
+ case nir_texop_tg4:
+ return emit_cube_tg4(ir, src);
+ case nir_texop_query_levels:
+ return emit_tex_txs(ir, src, {3,7,7,7});
+ default:
+ return false;
+ }
+ } else if (ir->sampler_dim == GLSL_SAMPLER_DIM_BUF) {
+ switch (ir->op) {
+ case nir_texop_txf:
+ return emit_buf_txf(ir, src);
+ case nir_texop_txs:
+ return emit_tex_txs(ir, src, {0,1,2,3});
+ default:
+ return false;
+ }
+ } else {
+ switch (ir->op) {
+ case nir_texop_tex:
+ return emit_tex_tex(ir, src);
+ case nir_texop_txf:
+ return emit_tex_txf(ir, src);
+ case nir_texop_txb:
+ return emit_tex_txb(ir, src);
+ case nir_texop_txl:
+ return emit_tex_txl(ir, src);
+ case nir_texop_txd:
+ return emit_tex_txd(ir, src);
+ case nir_texop_txs:
+ return emit_tex_txs(ir, src, {0,1,2,3});
+ case nir_texop_lod:
+ return emit_tex_lod(ir, src);
+ case nir_texop_tg4:
+ return emit_tex_tg4(ir, src);
+ case nir_texop_txf_ms:
+ return emit_tex_txf_ms(ir, src);
+ case nir_texop_query_levels:
+ return emit_tex_txs(ir, src, {3,7,7,7});
+ default:
+ return false;
+ }
+ }
+}
+
+bool EmitTexInstruction::emit_cube_txf(UNUSED nir_tex_instr* instr, UNUSED TexInputs &src)
+{
+ return false;
+}
+
+bool EmitTexInstruction::emit_cube_txd(nir_tex_instr* instr, TexInputs& tex_src)
+{
+
+ assert(instr->src[0].src.is_ssa);
+
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto tex_op = TexInstruction::sample_g;
+
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ GPRVector cubed(v);
+ emit_cube_prep(tex_src.coord, cubed, instr->is_array);
+
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ const uint16_t lookup[4] = {1, 0, 3, 2};
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = v[i];
+ src_elms[i] = cubed.reg_i(lookup[i]);
+ }
+
+ GPRVector empty_dst(0, {7,7,7,7});
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c_g;
+ }
+
+
+ PValue half(new LiteralValue(0.5f));
+ for (int i = 0; i < 3; ++i) {
+ emit_instruction(new AluInstruction(op2_mul_ieee, tex_src.ddx.reg_i(i), {tex_src.ddx.reg_i(i), half},
+ {alu_last_instr, alu_write}));
+ }
+ for (int i = 0; i < 3; ++i) {
+ emit_instruction(new AluInstruction(op2_mul_ieee, tex_src.ddy.reg_i(i), {tex_src.ddy.reg_i(i), half},
+ {alu_last_instr, alu_write}));
+ }
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect);
+
+ TexInstruction *irgh = new TexInstruction(TexInstruction::set_gradient_h, empty_dst, tex_src.ddx,
+ sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+ irgh->set_dest_swizzle({7,7,7,7});
+
+ TexInstruction *irgv = new TexInstruction(TexInstruction::set_gradient_v, empty_dst, tex_src.ddy,
+ sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+ irgv->set_dest_swizzle({7,7,7,7});
+
+ GPRVector dst(dst_elms);
+ GPRVector src(src_elms);
+ TexInstruction *ir = new TexInstruction(tex_op, dst, src, instr->sampler_index,
+ sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+
+ set_rect_coordinate_flags(instr, ir);
+ //set_offsets(ir, tex_src.offset);
+
+ emit_instruction(irgh);
+ emit_instruction(irgv);
+ emit_instruction(ir);
+ return true;
+}
+
+
+bool EmitTexInstruction::emit_cube_txl(nir_tex_instr* instr, TexInputs& tex_src)
+{
+ assert(instr->src[0].src.is_ssa);
+
+ if (instr->is_shadow)
+ return false;
+
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ GPRVector cubed(v);
+ emit_cube_prep(tex_src.coord, cubed, instr->is_array);
+
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ const uint16_t lookup[4] = {1, 0, 3, 2};
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = v[i];
+ src_elms[i] = cubed.reg_i(lookup[i]);
+ }
+
+ auto *ir = new AluInstruction(op1_mov, src_elms[3], tex_src.lod,
+ {alu_last_instr, alu_write});
+ emit_instruction(ir);
+
+ GPRVector src(src_elms);
+ GPRVector dst(dst_elms);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect);
+
+ auto tir = new TexInstruction(TexInstruction::sample_l, dst, src,
+ sampler.id,sampler.id + R600_MAX_CONST_BUFFERS,
+ tex_src.sampler_offset);
+
+ if (instr->is_array)
+ tir->set_flag(TexInstruction::z_unnormalized);
+
+ emit_instruction(tir);
+ return true;
+}
+
+bool EmitTexInstruction::emit_cube_lod(nir_tex_instr* instr, TexInputs& src)
+{
+ auto tex_op = TexInstruction::get_tex_lod;
+
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ GPRVector cubed(v);
+ emit_cube_prep(src.coord, cubed, instr->is_array);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect);
+
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, cubed, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS,
+ src.sampler_offset);
+
+ emit_instruction(irt);
+ return true;
+
+}
+
+
+bool EmitTexInstruction::emit_cube_txb(nir_tex_instr* instr, TexInputs& tex_src)
+{
+ assert(instr->src[0].src.is_ssa);
+
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ GPRVector cubed(v);
+ emit_cube_prep(tex_src.coord, cubed, instr->is_array);
+
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ const uint16_t lookup[4] = {1, 0, 3, 2};
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = v[i];
+ src_elms[i] = v[lookup[i]];
+ }
+
+ GPRVector src(src_elms);
+ GPRVector dst(dst_elms);
+
+ auto tex_op = TexInstruction::sample_lb;
+ if (!instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.bias,
+ {alu_last_instr, alu_write}));
+ } else {
+ emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c_lb;
+ }
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto tir = new TexInstruction(tex_op, dst, src,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+ emit_instruction(tir);
+ return true;
+
+}
+
+bool EmitTexInstruction::emit_cube_tex(nir_tex_instr* instr, TexInputs& tex_src)
+{
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ auto tex_op = TexInstruction::sample;
+ GPRVector cubed(v);
+ emit_cube_prep(tex_src.coord, cubed, instr->is_array);
+
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ const uint16_t lookup[4] = {1, 0, 3, 2};
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = v[i];
+ src_elms[i] = v[lookup[i]];
+ }
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c;
+ }
+
+ GPRVector dst(dst_elms);
+ GPRVector src(src_elms);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto tir = new TexInstruction(tex_op, dst, src,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+ if (instr->is_array)
+ tir->set_flag(TexInstruction::z_unnormalized);
+
+ emit_instruction(tir);
+ return true;
+
+}
+
+bool EmitTexInstruction::emit_cube_prep(const GPRVector& coord, GPRVector& cubed, bool is_array)
+{
+ AluInstruction *ir = nullptr;
+ const uint16_t src0_chan[4] = {2, 2, 0, 1};
+ const uint16_t src1_chan[4] = {1, 0, 2, 2};
+
+ for (int i = 0; i < 4; ++i) {
+ ir = new AluInstruction(op2_cube, cubed.reg_i(i), coord.reg_i(src0_chan[i]),
+ coord.reg_i(src1_chan[i]), {alu_write});
+
+ emit_instruction(ir);
+ }
+ ir->set_flag(alu_last_instr);
+
+ ir = new AluInstruction(op1_recip_ieee, cubed.reg_i(2), cubed.reg_i(2), {alu_write, alu_last_instr});
+ ir->set_flag(alu_src0_abs);
+ emit_instruction(ir);
+
+ PValue one_p_5(new LiteralValue(1.5f));
+ for (int i = 0; i < 2; ++i) {
+ ir = new AluInstruction(op3_muladd, cubed.reg_i(i), cubed.reg_i(i), cubed.reg_i(2),
+ one_p_5, {alu_write});
+ emit_instruction(ir);
+ }
+ ir->set_flag(alu_last_instr);
+
+ if (is_array) {
+ auto face = cubed.reg_i(3);
+ PValue array_index = get_temp_register();
+
+ ir = new AluInstruction(op1_rndne, array_index, coord.reg_i(3), {alu_write, alu_last_instr});
+ emit_instruction(ir);
+
+ ir = new AluInstruction(op2_max, array_index, {array_index, Value::zero}, {alu_write, alu_last_instr});
+ emit_instruction(ir);
+
+ ir = new AluInstruction(op3_muladd, face, {array_index, PValue (new LiteralValue(8.0f)), face},
+ {alu_write, alu_last_instr});
+ emit_instruction(ir);
+ }
+
+ return true;
+}
+
+bool EmitTexInstruction::emit_buf_txf(nir_tex_instr* instr, TexInputs &src)
+{
+ auto dst = make_dest(*instr);
+
+ auto ir = new FetchInstruction(vc_fetch, no_index_offset, dst, src.coord.reg_i(0), 0,
+ instr->texture_index + R600_MAX_CONST_BUFFERS,
+ PValue(), bim_none);
+ ir->set_flag(vtx_use_const_field);
+ emit_instruction(ir);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_tex(nir_tex_instr* instr, TexInputs& src)
+{
+
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto tex_op = TexInstruction::sample;
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect);
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c;
+ }
+
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ if (instr->is_array)
+ handle_array_index(*instr, src.coord, irt);
+
+ set_rect_coordinate_flags(instr, irt);
+ set_offsets(irt, src.offset);
+
+ emit_instruction(irt);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_txd(nir_tex_instr* instr, TexInputs& src)
+{
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto tex_op = TexInstruction::sample_g;
+ auto dst = make_dest(*instr);
+
+ GPRVector empty_dst(0,{7,7,7,7});
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c_g;
+ }
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ TexInstruction *irgh = new TexInstruction(TexInstruction::set_gradient_h, empty_dst, src.ddx,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ irgh->set_dest_swizzle({7,7,7,7});
+
+ TexInstruction *irgv = new TexInstruction(TexInstruction::set_gradient_v, empty_dst, src.ddy,
+ sampler.id, sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ irgv->set_dest_swizzle({7,7,7,7});
+
+ TexInstruction *ir = new TexInstruction(tex_op, dst, src.coord, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ if (instr->is_array)
+ handle_array_index(*instr, src.coord, ir);
+
+ set_rect_coordinate_flags(instr, ir);
+ set_offsets(ir, src.offset);
+
+ emit_instruction(irgh);
+ emit_instruction(irgv);
+ emit_instruction(ir);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_txf(nir_tex_instr* instr, TexInputs& src)
+{
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto dst = make_dest(*instr);
+
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.lod, {alu_write, alu_last_instr}));
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect);
+
+ /* txf doesn't need rounding for the array index, but 1D has the array index
+ * in the z component */
+ if (instr->is_array && instr->sampler_dim == GLSL_SAMPLER_DIM_1D)
+ src.coord.set_reg_i(2, src.coord.reg_i(1));
+
+ auto tex_ir = new TexInstruction(TexInstruction::ld, dst, src.coord,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+
+
+ if (src.offset) {
+ assert(src.offset->is_ssa);
+ AluInstruction *ir = nullptr;
+ for (unsigned i = 0; i < src.offset->ssa->num_components; ++i) {
+ ir = new AluInstruction(op2_add_int, src.coord.reg_i(i),
+ {src.coord.reg_i(i), from_nir(*src.offset, i, i)}, {alu_write});
+ emit_instruction(ir);
+ }
+ if (ir)
+ ir->set_flag(alu_last_instr);
+ }
+
+ emit_instruction(tex_ir);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_lod(nir_tex_instr* instr, TexInputs& src)
+{
+ auto tex_op = TexInstruction::get_tex_lod;
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ irt->set_dest_swizzle({1,0,7,7});
+ emit_instruction(irt);
+ return true;
+
+}
+
+bool EmitTexInstruction::emit_tex_txl(nir_tex_instr* instr, TexInputs& src)
+{
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto tex_op = TexInstruction::sample_l;
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.lod,
+ {alu_last_instr, alu_write}));
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(2), src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c_l;
+ }
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+
+ if (instr->is_array)
+ handle_array_index(*instr, src.coord, irt);
+
+ set_rect_coordinate_flags(instr, irt);
+ set_offsets(irt, src.offset);
+
+ emit_instruction(irt);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_txb(nir_tex_instr* instr, TexInputs& src)
+{
+ auto tex_op = TexInstruction::sample_lb;
+
+ std::array<uint8_t, 4> in_swizzle = {0,1,2,3};
+
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.bias,
+ {alu_last_instr, alu_write}));
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(2), src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::sample_c_lb;
+ }
+
+ GPRVector tex_src(src.coord, in_swizzle);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, tex_src, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ if (instr->is_array)
+ handle_array_index(*instr, tex_src, irt);
+
+ set_rect_coordinate_flags(instr, irt);
+ set_offsets(irt, src.offset);
+
+ emit_instruction(irt);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_txs(nir_tex_instr* instr, TexInputs& tex_src,
+ const std::array<int,4>& dest_swz)
+{
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = from_nir(instr->dest, (i < instr->dest.ssa.num_components) ? i : 7);
+ }
+
+ GPRVector dst(dst_elms);
+
+ if (instr->sampler_dim == GLSL_SAMPLER_DIM_BUF) {
+ emit_instruction(new FetchInstruction(dst, PValue(new GPRValue(0, 7)),
+ instr->sampler_index + R600_MAX_CONST_BUFFERS,
+ bim_none));
+ } else {
+ for (uint16_t i = 0; i < 4; ++i)
+ src_elms[i] = tex_src.lod;
+ GPRVector src(src_elms);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto ir = new TexInstruction(TexInstruction::get_resinfo, dst, src,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+ ir->set_dest_swizzle(dest_swz);
+ emit_instruction(ir);
+ }
+
+ return true;
+
+}
+
+bool EmitTexInstruction::emit_tex_tg4(nir_tex_instr* instr, TexInputs& src)
+{
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto tex_op = TexInstruction::gather4;
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3), src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::gather4_c;
+ }
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ bool literal_offset = false;
+ if (src.offset) {
+ literal_offset = src.offset->is_ssa && get_literal_register(*src.offset);
+ r600::sfn_log << SfnLog::tex << " really have offsets and they are " <<
+ (literal_offset ? "literal" : "varying") <<
+ "\n";
+
+ if (!literal_offset) {
+ GPRVector::Swizzle swizzle = {4,4,4,4};
+ for (unsigned i = 0; i < instr->coord_components; ++i)
+ swizzle[i] = i;
+
+ std::unique_ptr<GPRVector> ofs(vec_from_nir_with_fetch_constant(*src.offset,
+ ( 1 << instr->coord_components) -1,
+ swizzle));
+ GPRVector dummy(0, {7,7,7,7});
+ tex_op = (tex_op == TexInstruction::gather4_c) ?
+ TexInstruction::gather4_c_o : TexInstruction::gather4_o;
+
+ auto set_ofs = new TexInstruction(TexInstruction::set_offsets, dummy,
+ *ofs, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ set_ofs->set_dest_swizzle({7,7,7,7});
+ emit_instruction(set_ofs);
+ }
+ }
+
+
+ /* pre CAYMAN needs swizzle */
+ auto dst = make_dest(*instr);
+ auto irt = new TexInstruction(tex_op, dst, src.coord, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+
+ irt->set_dest_swizzle({1,2,0,3});
+ irt->set_gather_comp(instr->component);
+
+ if (instr->is_array)
+ handle_array_index(*instr, src.coord, irt);
+
+ if (literal_offset) {
+ r600::sfn_log << SfnLog::tex << "emit literal offsets\n";
+ set_offsets(irt, src.offset);
+ }
+
+ set_rect_coordinate_flags(instr, irt);
+
+ emit_instruction(irt);
+ return true;
+}
+
+bool EmitTexInstruction::emit_cube_tg4(nir_tex_instr* instr, TexInputs& tex_src)
+{
+ std::array<PValue, 4> v;
+ for (int i = 0; i < 4; ++i)
+ v[i] = from_nir(instr->dest, i);
+
+ auto tex_op = TexInstruction::gather4;
+ GPRVector cubed(v);
+ emit_cube_prep(tex_src.coord, cubed, instr->is_array);
+
+ std::array<PValue,4> dst_elms;
+ std::array<PValue,4> src_elms;
+
+ const uint16_t lookup[4] = {1, 0, 3, 2};
+ for (uint16_t i = 0; i < 4; ++i) {
+ dst_elms[i] = v[i];
+ src_elms[i] = v[lookup[i]];
+ }
+
+ if (instr->is_shadow) {
+ emit_instruction(new AluInstruction(op1_mov, src_elms[3], tex_src.comperator,
+ {alu_last_instr, alu_write}));
+ tex_op = TexInstruction::gather4_c;
+ }
+
+ GPRVector dst(dst_elms);
+ GPRVector src(src_elms);
+
+ auto sampler = get_samplerr_id(instr->sampler_index, tex_src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ auto tir = new TexInstruction(tex_op, dst, src, sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, tex_src.sampler_offset);
+
+ tir->set_gather_comp(instr->component);
+
+ tir->set_dest_swizzle({1, 2, 0, 3});
+
+ if (instr->is_array)
+ tir->set_flag(TexInstruction::z_unnormalized);
+
+ emit_instruction(tir);
+ return true;
+}
+
+bool EmitTexInstruction::emit_tex_txf_ms(nir_tex_instr* instr, TexInputs& src)
+{
+ assert(instr->src[0].src.is_ssa);
+
+ r600::sfn_log << SfnLog::instr << "emit '"
+ << *reinterpret_cast<nir_instr*>(instr)
+ << "' (" << __func__ << ")\n";
+
+ auto sampler = get_samplerr_id(instr->sampler_index, src.sampler_deref);
+ assert(!sampler.indirect && "Indirect sampler selection not yet supported");
+
+ int sample_id = allocate_temp_register();
+
+ GPRVector sample_id_dest(sample_id, {0,7,7,7});
+ PValue help(new GPRValue(sample_id, 1));
+
+ /* FIXME: Texture destination registers must be handled differently,
+ * because the swizzle identfies which source componnet has to be written
+ * at a certain position, and the target register is actually different.
+ * At this point we just add a helper register, but for later work (scheduling
+ * and optimization on the r600 IR level, this needs to be implemented
+ * differently */
+
+
+ emit_instruction(new AluInstruction(op1_mov, src.coord.reg_i(3),
+ src.ms_index,
+ {alu_write, alu_last_instr}));
+
+ auto tex_sample_id_ir = new TexInstruction(TexInstruction::ld, sample_id_dest, src.coord,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+ tex_sample_id_ir->set_flag(TexInstruction::x_unnormalized);
+ tex_sample_id_ir->set_flag(TexInstruction::y_unnormalized);
+ tex_sample_id_ir->set_flag(TexInstruction::z_unnormalized);
+ tex_sample_id_ir->set_flag(TexInstruction::w_unnormalized);
+ tex_sample_id_ir->set_inst_mode(1);
+
+ emit_instruction(tex_sample_id_ir);
+
+ emit_instruction(new AluInstruction(op2_mullo_int, help,
+ {src.ms_index, PValue(new LiteralValue(4))},
+ {alu_write, alu_last_instr}));
+
+ emit_instruction(new AluInstruction(op2_lshr_int, src.coord.reg_i(3),
+ {sample_id_dest.reg_i(0), help},
+ {alu_write, alu_last_instr}));
+
+ emit_instruction(new AluInstruction(op2_and_int, src.coord.reg_i(3),
+ {src.coord.reg_i(3), PValue(new LiteralValue(15))},
+ {alu_write, alu_last_instr}));
+
+ auto dst = make_dest(*instr);
+
+ /* txf doesn't need rounding for the array index, but 1D has the array index
+ * in the z component */
+ if (instr->is_array && instr->sampler_dim == GLSL_SAMPLER_DIM_1D)
+ src.coord.set_reg_i(2, src.coord.reg_i(1));
+
+ auto tex_ir = new TexInstruction(TexInstruction::ld, dst, src.coord,
+ sampler.id,
+ sampler.id + R600_MAX_CONST_BUFFERS, src.sampler_offset);
+
+
+ if (src.offset) {
+ assert(src.offset->is_ssa);
+ AluInstruction *ir = nullptr;
+ for (unsigned i = 0; i < src.offset->ssa->num_components; ++i) {
+ ir = new AluInstruction(op2_add_int, src.coord.reg_i(i),
+ {src.coord.reg_i(i), from_nir(*src.offset, i, i)}, {alu_write});
+ emit_instruction(ir);
+ }
+ if (ir)
+ ir->set_flag(alu_last_instr);
+ }
+
+ emit_instruction(tex_ir);
+ return true;
+}
+
+bool EmitTexInstruction::get_inputs(const nir_tex_instr& instr, TexInputs &src)
+{
+ sfn_log << SfnLog::tex << "Get Inputs with " << instr.coord_components << " components\n";
+
+ unsigned grad_components = instr.coord_components;
+ if (instr.is_array)
+ --grad_components;
+
+
+ src.offset = nullptr;
+ bool retval = true;
+ for (unsigned i = 0; i < instr.num_srcs; ++i) {
+ switch (instr.src[i].src_type) {
+ case nir_tex_src_bias:
+ src.bias = from_nir(instr.src[i], 0);
+ break;
+
+ case nir_tex_src_coord: {
+ std::unique_ptr<GPRVector> coord(vec_from_nir_with_fetch_constant(instr.src[i].src,
+ (1 << instr.coord_components) - 1,
+ {0,1,2,3}));
+ src.coord = *coord;
+
+ } break;
+ case nir_tex_src_comparator:
+ src.comperator = from_nir(instr.src[i], 0);
+ break;
+ case nir_tex_src_ddx: {
+ sfn_log << SfnLog::tex << "Get DDX ";
+ std::unique_ptr<GPRVector> coord(vec_from_nir_with_fetch_constant(instr.src[i].src,
+ (1 << grad_components) - 1,
+ swizzle_from_mask(grad_components)));
+ src.ddx = *coord;
+ sfn_log << SfnLog::tex << src.ddx << "\n";
+ } break;
+ case nir_tex_src_ddy:{
+ sfn_log << SfnLog::tex << "Get DDY ";
+ std::unique_ptr<GPRVector> coord(vec_from_nir_with_fetch_constant(instr.src[i].src,
+ (1 << grad_components) - 1,
+ swizzle_from_mask(grad_components)));
+ src.ddy = *coord;
+ sfn_log << SfnLog::tex << src.ddy << "\n";
+ } break;
+ case nir_tex_src_lod:
+ src.lod = from_nir_with_fetch_constant(instr.src[i].src, 0);
+ break;
+ case nir_tex_src_offset:
+ sfn_log << SfnLog::tex << " -- Find offset\n";
+ src.offset = &instr.src[i].src;
+ break;
+ case nir_tex_src_sampler_deref:
+ src.sampler_deref = get_deref_location(instr.src[i].src);
+ break;
+ case nir_tex_src_texture_deref:
+ src.texture_deref = get_deref_location(instr.src[i].src);
+ break;
+ case nir_tex_src_ms_index:
+ src.ms_index = from_nir(instr.src[i], 0);
+ break;
+ case nir_tex_src_texture_offset:
+ src.texture_offset = from_nir(instr.src[i], 0);
+ break;
+ case nir_tex_src_sampler_offset:
+ src.sampler_offset = from_nir(instr.src[i], 0);
+ break;
+ case nir_tex_src_plane:
+ case nir_tex_src_projector:
+ case nir_tex_src_min_lod:
+ case nir_tex_src_ms_mcs:
+ default:
+ sfn_log << SfnLog::tex << "Texture source type " << instr.src[i].src_type << " not supported\n";
+ retval = false;
+ }
+ }
+ return retval;
+}
+
+GPRVector EmitTexInstruction::make_dest(nir_tex_instr& instr)
+{
+ int num_dest_components = instr.dest.is_ssa ? instr.dest.ssa.num_components :
+ instr.dest.reg.reg->num_components;
+ std::array<PValue,4> dst_elms;
+ for (uint16_t i = 0; i < 4; ++i)
+ dst_elms[i] = from_nir(instr.dest, (i < num_dest_components) ? i : 7);
+ return GPRVector(dst_elms);
+}
+
+
+GPRVector EmitTexInstruction::make_dest(nir_tex_instr& instr,
+ const std::array<int, 4>& swizzle)
+{
+ int num_dest_components = instr.dest.is_ssa ? instr.dest.ssa.num_components :
+ instr.dest.reg.reg->num_components;
+ std::array<PValue,4> dst_elms;
+ for (uint16_t i = 0; i < 4; ++i) {
+ int k = swizzle[i];
+ dst_elms[i] = from_nir(instr.dest, (k < num_dest_components) ? k : 7);
+ }
+ return GPRVector(dst_elms);
+}
+
+void EmitTexInstruction::set_rect_coordinate_flags(nir_tex_instr* instr,
+ TexInstruction* ir) const
+{
+ if (instr->sampler_dim == GLSL_SAMPLER_DIM_RECT) {
+ ir->set_flag(TexInstruction::x_unnormalized);
+ ir->set_flag(TexInstruction::y_unnormalized);
+ }
+}
+
+void EmitTexInstruction::set_offsets(TexInstruction* ir, nir_src *offset)
+{
+ if (!offset)
+ return;
+
+ assert(offset->is_ssa);
+ auto literal = get_literal_register(*offset);
+ assert(literal);
+
+ for (int i = 0; i < offset->ssa->num_components; ++i) {
+ ir->set_offset(i, literal->value[i].i32);
+ }
+}
+
+void EmitTexInstruction::handle_array_index(const nir_tex_instr& instr, const GPRVector& src, TexInstruction *ir)
+{
+ int src_idx = instr.sampler_dim == GLSL_SAMPLER_DIM_1D ? 1 : 2;
+ emit_instruction(new AluInstruction(op1_rndne, src.reg_i(2), src.reg_i(src_idx),
+ {alu_last_instr, alu_write}));
+ ir->set_flag(TexInstruction::z_unnormalized);
+}
+
+EmitTexInstruction::SamplerId
+EmitTexInstruction::get_samplerr_id(int sampler_id, const nir_variable *deref)
+{
+ EmitTexInstruction::SamplerId result = {sampler_id, false};
+
+ if (deref) {
+ assert(glsl_type_is_sampler(deref->type));
+ result.id = deref->data.binding;
+ }
+ return result;
+}
+
+EmitTexInstruction::TexInputs::TexInputs():
+ sampler_deref(nullptr),
+ texture_deref(nullptr),
+ offset(nullptr)
+{
+}
+
+}