diff options
author | Gert Wollny <[email protected]> | 2019-12-01 20:38:07 +0100 |
---|---|---|
committer | Marge Bot <[email protected]> | 2020-02-10 19:09:08 +0000 |
commit | f718ac62688b555a933c7112f656944288d04edb (patch) | |
tree | 618add486794d43e1efe04e8668e4196e5e9c1ef /src/gallium/drivers/r600/sfn/sfn_emittexinstruction.cpp | |
parent | 295be0e8dfcc28366bcd193c44abc7913d5132d8 (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.cpp | 974 |
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) +{ +} + +} |