+/**
+ * Lowers texture instructions from giving a vec4 result to a vec2 of f16,
+ * i16, or u16, or a single unorm4x8 value.
+ *
+ * Note that we don't change the destination num_components, because
+ * nir_tex_instr_dest_size() will still return 4. The driver is just expected
+ * to not store the other channels, given that nothing at the NIR level will
+ * read them.
+ */
+static void
+lower_tex_packing(nir_builder *b, nir_tex_instr *tex,
+ const nir_lower_tex_options *options)
+{
+ nir_ssa_def *color = &tex->dest.ssa;
+
+ b->cursor = nir_after_instr(&tex->instr);
+
+ switch (options->lower_tex_packing[tex->sampler_index]) {
+ case nir_lower_tex_packing_none:
+ return;
+
+ case nir_lower_tex_packing_16: {
+ static const unsigned bits[4] = {16, 16, 16, 16};
+
+ switch (nir_alu_type_get_base_type(tex->dest_type)) {
+ case nir_type_float:
+ switch (nir_tex_instr_dest_size(tex)) {
+ case 1:
+ assert(tex->is_shadow && tex->is_new_style_shadow);
+ color = nir_unpack_half_2x16_split_x(b, nir_channel(b, color, 0));
+ break;
+ case 2: {
+ nir_ssa_def *rg = nir_channel(b, color, 0);
+ color = nir_vec2(b,
+ nir_unpack_half_2x16_split_x(b, rg),
+ nir_unpack_half_2x16_split_y(b, rg));
+ break;
+ }
+ case 4: {
+ nir_ssa_def *rg = nir_channel(b, color, 0);
+ nir_ssa_def *ba = nir_channel(b, color, 1);
+ color = nir_vec4(b,
+ nir_unpack_half_2x16_split_x(b, rg),
+ nir_unpack_half_2x16_split_y(b, rg),
+ nir_unpack_half_2x16_split_x(b, ba),
+ nir_unpack_half_2x16_split_y(b, ba));
+ break;
+ }
+ default:
+ unreachable("wrong dest_size");
+ }
+ break;
+
+ case nir_type_int:
+ color = nir_format_unpack_sint(b, color, bits, 4);
+ break;
+
+ case nir_type_uint:
+ color = nir_format_unpack_uint(b, color, bits, 4);
+ break;
+
+ default:
+ unreachable("unknown base type");
+ }
+ break;
+ }
+
+ case nir_lower_tex_packing_8:
+ assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
+ color = nir_unpack_unorm_4x8(b, nir_channel(b, color, 0));
+ break;
+ }
+
+ nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, nir_src_for_ssa(color),
+ color->parent_instr);
+}
+
+static bool
+sampler_index_lt(nir_tex_instr *tex, unsigned max)
+{
+ assert(nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref) == -1);
+
+ unsigned sampler_index = tex->sampler_index;
+
+ int sampler_offset_idx =
+ nir_tex_instr_src_index(tex, nir_tex_src_sampler_offset);
+ if (sampler_offset_idx >= 0) {
+ if (!nir_src_is_const(tex->src[sampler_offset_idx].src))
+ return false;
+
+ sampler_index += nir_src_as_uint(tex->src[sampler_offset_idx].src);
+ }
+
+ return sampler_index < max;
+}
+
+static bool
+lower_tg4_offsets(nir_builder *b, nir_tex_instr *tex)
+{
+ assert(tex->op == nir_texop_tg4);
+ assert(nir_tex_instr_has_explicit_tg4_offsets(tex));
+ assert(nir_tex_instr_src_index(tex, nir_tex_src_offset) == -1);
+
+ b->cursor = nir_after_instr(&tex->instr);
+
+ nir_ssa_def *dest[4];
+ for (unsigned i = 0; i < 4; ++i) {
+ nir_tex_instr *tex_copy = nir_tex_instr_create(b->shader, tex->num_srcs + 1);
+ tex_copy->op = tex->op;
+ tex_copy->coord_components = tex->coord_components;
+ tex_copy->sampler_dim = tex->sampler_dim;
+ tex_copy->is_array = tex->is_array;
+ tex_copy->is_shadow = tex->is_shadow;
+ tex_copy->is_new_style_shadow = tex->is_new_style_shadow;
+ tex_copy->component = tex->component;
+ tex_copy->dest_type = tex->dest_type;
+
+ for (unsigned j = 0; j < tex->num_srcs; ++j) {
+ nir_src_copy(&tex_copy->src[j].src, &tex->src[j].src, tex_copy);
+ tex_copy->src[j].src_type = tex->src[j].src_type;
+ }
+
+ nir_tex_src src;
+ src.src = nir_src_for_ssa(nir_imm_ivec2(b, tex->tg4_offsets[i][0],
+ tex->tg4_offsets[i][1]));
+ src.src_type = nir_tex_src_offset;
+ tex_copy->src[tex_copy->num_srcs - 1] = src;
+
+ nir_ssa_dest_init(&tex_copy->instr, &tex_copy->dest,
+ nir_tex_instr_dest_size(tex), 32, NULL);
+
+ nir_builder_instr_insert(b, &tex_copy->instr);
+
+ dest[i] = nir_channel(b, &tex_copy->dest.ssa, 3);
+ }
+
+ nir_ssa_def *res = nir_vec4(b, dest[0], dest[1], dest[2], dest[3]);
+ nir_ssa_def_rewrite_uses(&tex->dest.ssa, nir_src_for_ssa(res));
+ nir_instr_remove(&tex->instr);
+
+ return true;
+}
+
+static bool
+nir_lower_txs_lod(nir_builder *b, nir_tex_instr *tex)
+{
+ int lod_idx = nir_tex_instr_src_index(tex, nir_tex_src_lod);
+ if (lod_idx < 0 ||
+ (nir_src_is_const(tex->src[lod_idx].src) &&
+ nir_src_as_int(tex->src[lod_idx].src) == 0))
+ return false;
+
+ unsigned dest_size = nir_tex_instr_dest_size(tex);
+
+ b->cursor = nir_before_instr(&tex->instr);
+ nir_ssa_def *lod = nir_ssa_for_src(b, tex->src[lod_idx].src, 1);
+
+ /* Replace the non-0-LOD in the initial TXS operation by a 0-LOD. */
+ nir_instr_rewrite_src(&tex->instr, &tex->src[lod_idx].src,
+ nir_src_for_ssa(nir_imm_int(b, 0)));
+
+ /* TXS(LOD) = max(TXS(0) >> LOD, 1) */
+ b->cursor = nir_after_instr(&tex->instr);
+ nir_ssa_def *minified = nir_imax(b, nir_ushr(b, &tex->dest.ssa, lod),
+ nir_imm_int(b, 1));
+
+ /* Make sure the component encoding the array size (if any) is not
+ * minified.
+ */
+ if (tex->is_array) {
+ nir_ssa_def *comp[3];
+
+ assert(dest_size <= ARRAY_SIZE(comp));
+ for (unsigned i = 0; i < dest_size - 1; i++)
+ comp[i] = nir_channel(b, minified, i);
+
+ comp[dest_size - 1] = nir_channel(b, &tex->dest.ssa, dest_size - 1);
+ minified = nir_vec(b, comp, dest_size);
+ }
+
+ nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, nir_src_for_ssa(minified),
+ minified->parent_instr);
+ return true;
+}
+