+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;
+}
+