diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c
index 4b79a058b6ffa0eb5d3ecdbee6fbc0c42b161a1d..a817f76f40ce772c0bee3b3fbb420812d2bcf7e5 100644
--- a/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d-shader/ir.c
@@ -127,23 +127,134 @@ const struct vkd3d_shader_parameter1 *vsir_program_get_parameter(
     return NULL;
 }
 
+void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type,
+        enum vkd3d_data_type data_type, unsigned int idx_count)
+{
+    reg->type = reg_type;
+    reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT;
+    reg->non_uniform = false;
+    reg->data_type = data_type;
+    reg->idx[0].offset = ~0u;
+    reg->idx[0].rel_addr = NULL;
+    reg->idx[0].is_in_bounds = false;
+    reg->idx[1].offset = ~0u;
+    reg->idx[1].rel_addr = NULL;
+    reg->idx[1].is_in_bounds = false;
+    reg->idx[2].offset = ~0u;
+    reg->idx[2].rel_addr = NULL;
+    reg->idx[2].is_in_bounds = false;
+    reg->idx_count = idx_count;
+    reg->dimension = VSIR_DIMENSION_SCALAR;
+    reg->alignment = 0;
+}
+
 static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg)
 {
     return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID;
 }
 
-static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction)
+void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type,
+        enum vkd3d_data_type data_type, unsigned int idx_count)
 {
-    enum vkd3d_shader_opcode opcode = instruction->opcode;
-    return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT)
-            || opcode == VKD3DSIH_HS_DECLS;
+    vsir_register_init(&param->reg, reg_type, data_type, idx_count);
+    param->swizzle = 0;
+    param->modifiers = VKD3DSPSM_NONE;
 }
 
-static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins)
+static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value)
 {
-    struct vkd3d_shader_location location = ins->location;
+    vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0);
+    src->reg.u.immconst_u32[0] = value;
+}
 
-    vsir_instruction_init(ins, &location, VKD3DSIH_NOP);
+void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id)
+{
+    vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1);
+    param->reg.dimension = VSIR_DIMENSION_NONE;
+    param->reg.idx[0].offset = label_id;
+}
+
+static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type)
+{
+    vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1);
+    src->reg.idx[0].offset = idx;
+}
+
+static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_RESOURCE, 2);
+    src->reg.idx[0].offset = id;
+    src->reg.idx[1].offset = idx;
+    src->reg.dimension = VSIR_DIMENSION_VEC4;
+    src->swizzle = VKD3D_SHADER_NO_SWIZZLE;
+}
+
+static void vsir_src_param_init_sampler(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_SAMPLER, VKD3D_DATA_SAMPLER, 2);
+    src->reg.idx[0].offset = id;
+    src->reg.idx[1].offset = idx;
+    src->reg.dimension = VSIR_DIMENSION_NONE;
+}
+
+static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
+    src->reg.idx[0].offset = idx;
+}
+
+static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
+    src->reg.idx[0].offset = idx;
+}
+
+static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
+    src->reg.idx[0].offset = idx;
+}
+
+static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+    src->reg.idx[0].offset = idx;
+}
+
+void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type,
+        enum vkd3d_data_type data_type, unsigned int idx_count)
+{
+    vsir_register_init(&param->reg, reg_type, data_type, idx_count);
+    param->write_mask = VKD3DSP_WRITEMASK_0;
+    param->modifiers = VKD3DSPDM_NONE;
+    param->shift = 0;
+}
+
+static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
+{
+    vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
+    dst->reg.idx[0].offset = idx;
+}
+
+static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
+{
+    vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
+    dst->reg.idx[0].offset = idx;
+}
+
+static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx)
+{
+    vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+    dst->reg.idx[0].offset = idx;
+    dst->write_mask = VKD3DSP_WRITEMASK_0;
+}
+
+void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
+        enum vkd3d_shader_opcode opcode)
+{
+    memset(ins, 0, sizeof(*ins));
+    ins->location = *location;
+    ins->opcode = opcode;
 }
 
 bool vsir_instruction_init_with_params(struct vsir_program *program,
@@ -171,6 +282,37 @@ bool vsir_instruction_init_with_params(struct vsir_program *program,
     return true;
 }
 
+static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins,
+        const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program)
+{
+    struct vkd3d_shader_src_param *src_param;
+
+    if (!(src_param = vsir_program_get_src_params(program, 1)))
+        return false;
+
+    vsir_src_param_init_label(src_param, label_id);
+
+    vsir_instruction_init(ins, location, VKD3DSIH_LABEL);
+    ins->src = src_param;
+    ins->src_count = 1;
+
+    return true;
+}
+
+static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction)
+{
+    enum vkd3d_shader_opcode opcode = instruction->opcode;
+    return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT)
+            || opcode == VKD3DSIH_HS_DECLS;
+}
+
+static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins)
+{
+    struct vkd3d_shader_location location = ins->location;
+
+    vsir_instruction_init(ins, &location, VKD3DSIH_NOP);
+}
+
 static bool get_opcode_from_rel_op(enum vkd3d_shader_rel_op rel_op, enum vkd3d_data_type data_type,
         enum vkd3d_shader_opcode *opcode, bool *requires_swap)
 {
@@ -451,6 +593,53 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog
     return VKD3D_OK;
 }
 
+static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *tex)
+{
+    unsigned int idx = tex->src[1].reg.idx[0].offset;
+    struct vkd3d_shader_src_param *srcs;
+
+    VKD3D_ASSERT(tex->src[1].reg.idx_count == 1);
+    VKD3D_ASSERT(!tex->src[1].reg.idx[0].rel_addr);
+
+    if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3)))
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+
+    srcs[0] = tex->src[0];
+    vsir_src_param_init_resource(&srcs[1], idx, idx);
+    vsir_src_param_init_sampler(&srcs[2], idx, idx);
+
+    tex->opcode = VKD3DSIH_SAMPLE;
+    tex->src = srcs;
+    tex->src_count = 3;
+
+    return VKD3D_OK;
+}
+
+static enum vkd3d_result vsir_program_lower_texldd(struct vsir_program *program,
+        struct vkd3d_shader_instruction *texldd)
+{
+    unsigned int idx = texldd->src[1].reg.idx[0].offset;
+    struct vkd3d_shader_src_param *srcs;
+
+    VKD3D_ASSERT(texldd->src[1].reg.idx_count == 1);
+    VKD3D_ASSERT(!texldd->src[1].reg.idx[0].rel_addr);
+
+    if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5)))
+        return VKD3D_ERROR_OUT_OF_MEMORY;
+
+    srcs[0] = texldd->src[0];
+    vsir_src_param_init_resource(&srcs[1], idx, idx);
+    vsir_src_param_init_sampler(&srcs[2], idx, idx);
+    srcs[3] = texldd->src[2];
+    srcs[4] = texldd->src[3];
+
+    texldd->opcode = VKD3DSIH_SAMPLE_GRAD;
+    texldd->src = srcs;
+    texldd->src_count = 5;
+
+    return VKD3D_OK;
+}
+
 static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *program,
         struct vsir_transformation_context *ctx)
 {
@@ -492,6 +681,38 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr
                     return ret;
                 break;
 
+            case VKD3DSIH_TEX:
+                if ((ret = vsir_program_lower_tex(program, ins)) < 0)
+                    return ret;
+                break;
+
+            case VKD3DSIH_TEXLDD:
+                if ((ret = vsir_program_lower_texldd(program, ins)) < 0)
+                    return ret;
+                break;
+
+            case VKD3DSIH_TEXBEM:
+            case VKD3DSIH_TEXBEML:
+            case VKD3DSIH_TEXCOORD:
+            case VKD3DSIH_TEXDEPTH:
+            case VKD3DSIH_TEXDP3:
+            case VKD3DSIH_TEXDP3TEX:
+            case VKD3DSIH_TEXLDL:
+            case VKD3DSIH_TEXM3x2PAD:
+            case VKD3DSIH_TEXM3x2TEX:
+            case VKD3DSIH_TEXM3x3DIFF:
+            case VKD3DSIH_TEXM3x3PAD:
+            case VKD3DSIH_TEXM3x3SPEC:
+            case VKD3DSIH_TEXM3x3TEX:
+            case VKD3DSIH_TEXM3x3VSPEC:
+            case VKD3DSIH_TEXREG2AR:
+            case VKD3DSIH_TEXREG2GB:
+            case VKD3DSIH_TEXREG2RGB:
+                vkd3d_shader_error(ctx->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
+                        "Aborting due to unimplemented feature: Combined sampler instruction %#x.",
+                        ins->opcode);
+                return VKD3D_ERROR_NOT_IMPLEMENTED;
+
             default:
                 break;
         }
@@ -740,131 +961,6 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali
     return VKD3D_OK;
 }
 
-void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type,
-        enum vkd3d_data_type data_type, unsigned int idx_count)
-{
-    reg->type = reg_type;
-    reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT;
-    reg->non_uniform = false;
-    reg->data_type = data_type;
-    reg->idx[0].offset = ~0u;
-    reg->idx[0].rel_addr = NULL;
-    reg->idx[0].is_in_bounds = false;
-    reg->idx[1].offset = ~0u;
-    reg->idx[1].rel_addr = NULL;
-    reg->idx[1].is_in_bounds = false;
-    reg->idx[2].offset = ~0u;
-    reg->idx[2].rel_addr = NULL;
-    reg->idx[2].is_in_bounds = false;
-    reg->idx_count = idx_count;
-    reg->dimension = VSIR_DIMENSION_SCALAR;
-    reg->alignment = 0;
-}
-
-void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type,
-        enum vkd3d_data_type data_type, unsigned int idx_count)
-{
-    vsir_register_init(&param->reg, reg_type, data_type, idx_count);
-    param->swizzle = 0;
-    param->modifiers = VKD3DSPSM_NONE;
-}
-
-void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type,
-        enum vkd3d_data_type data_type, unsigned int idx_count)
-{
-    vsir_register_init(&param->reg, reg_type, data_type, idx_count);
-    param->write_mask = VKD3DSP_WRITEMASK_0;
-    param->modifiers = VKD3DSPDM_NONE;
-    param->shift = 0;
-}
-
-void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id)
-{
-    vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1);
-    param->reg.dimension = VSIR_DIMENSION_NONE;
-    param->reg.idx[0].offset = label_id;
-}
-
-static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
-{
-    vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
-    src->reg.idx[0].offset = idx;
-}
-
-static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
-{
-    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
-    src->reg.idx[0].offset = idx;
-}
-
-static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
-{
-    vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
-    dst->reg.idx[0].offset = idx;
-}
-
-static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
-{
-    vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
-    dst->reg.idx[0].offset = idx;
-}
-
-static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx)
-{
-    vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
-    dst->reg.idx[0].offset = idx;
-    dst->write_mask = VKD3DSP_WRITEMASK_0;
-}
-
-static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx)
-{
-    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
-    src->reg.idx[0].offset = idx;
-}
-
-static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx)
-{
-    vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
-    src->reg.idx[0].offset = idx;
-}
-
-static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value)
-{
-    vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0);
-    src->reg.u.immconst_u32[0] = value;
-}
-
-static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type)
-{
-    vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1);
-    src->reg.idx[0].offset = idx;
-}
-
-void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
-        enum vkd3d_shader_opcode opcode)
-{
-    memset(ins, 0, sizeof(*ins));
-    ins->location = *location;
-    ins->opcode = opcode;
-}
-
-static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins,
-        const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program)
-{
-    struct vkd3d_shader_src_param *src_param;
-
-    if (!(src_param = vsir_program_get_src_params(program, 1)))
-        return false;
-
-    vsir_src_param_init_label(src_param, label_id);
-
-    vsir_instruction_init(ins, location, VKD3DSIH_LABEL);
-    ins->src = src_param;
-    ins->src_count = 1;
-
-    return true;
-}
-
 static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program,
         struct vsir_transformation_context *ctx)
 {
@@ -2055,106 +2151,6 @@ static enum vkd3d_result vsir_program_remove_dead_code(struct vsir_program *prog
     return VKD3D_OK;
 }
 
-static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_program *program,
-        struct vsir_transformation_context *ctx)
-{
-    unsigned int i;
-
-    for (i = 0; i < program->instructions.count; ++i)
-    {
-        struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
-        struct vkd3d_shader_src_param *srcs;
-
-        switch (ins->opcode)
-        {
-            case VKD3DSIH_TEX:
-                if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3)))
-                    return VKD3D_ERROR_OUT_OF_MEMORY;
-                memset(srcs, 0, sizeof(*srcs) * 3);
-
-                ins->opcode = VKD3DSIH_SAMPLE;
-
-                srcs[0] = ins->src[0];
-
-                srcs[1].reg.type = VKD3DSPR_RESOURCE;
-                srcs[1].reg.idx[0] = ins->src[1].reg.idx[0];
-                srcs[1].reg.idx[1] = ins->src[1].reg.idx[0];
-                srcs[1].reg.idx_count = 2;
-                srcs[1].reg.data_type = VKD3D_DATA_RESOURCE;
-                srcs[1].reg.dimension = VSIR_DIMENSION_VEC4;
-                srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE;
-
-                srcs[2].reg.type = VKD3DSPR_SAMPLER;
-                srcs[2].reg.idx[0] = ins->src[1].reg.idx[0];
-                srcs[2].reg.idx[1] = ins->src[1].reg.idx[0];
-                srcs[2].reg.idx_count = 2;
-                srcs[2].reg.data_type = VKD3D_DATA_SAMPLER;
-
-                ins->src = srcs;
-                ins->src_count = 3;
-                break;
-
-            case VKD3DSIH_TEXLDD:
-                if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5)))
-                    return VKD3D_ERROR_OUT_OF_MEMORY;
-                memset(srcs, 0, sizeof(*srcs) * 5);
-
-                ins->opcode = VKD3DSIH_SAMPLE_GRAD;
-
-                srcs[0] = ins->src[0];
-
-                srcs[1].reg.type = VKD3DSPR_RESOURCE;
-                srcs[1].reg.idx[0] = ins->src[1].reg.idx[0];
-                srcs[1].reg.idx[1] = ins->src[1].reg.idx[0];
-                srcs[1].reg.idx_count = 2;
-                srcs[1].reg.data_type = VKD3D_DATA_RESOURCE;
-                srcs[1].reg.dimension = VSIR_DIMENSION_VEC4;
-                srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE;
-
-                srcs[2].reg.type = VKD3DSPR_SAMPLER;
-                srcs[2].reg.idx[0] = ins->src[1].reg.idx[0];
-                srcs[2].reg.idx[1] = ins->src[1].reg.idx[0];
-                srcs[2].reg.idx_count = 2;
-                srcs[2].reg.data_type = VKD3D_DATA_SAMPLER;
-
-                srcs[3] = ins->src[2];
-                srcs[4] = ins->src[3];
-
-                ins->src = srcs;
-                ins->src_count = 5;
-                break;
-
-            case VKD3DSIH_TEXBEM:
-            case VKD3DSIH_TEXBEML:
-            case VKD3DSIH_TEXCOORD:
-            case VKD3DSIH_TEXDEPTH:
-            case VKD3DSIH_TEXDP3:
-            case VKD3DSIH_TEXDP3TEX:
-            case VKD3DSIH_TEXLDL:
-            case VKD3DSIH_TEXM3x2PAD:
-            case VKD3DSIH_TEXM3x2TEX:
-            case VKD3DSIH_TEXM3x3DIFF:
-            case VKD3DSIH_TEXM3x3PAD:
-            case VKD3DSIH_TEXM3x3SPEC:
-            case VKD3DSIH_TEXM3x3TEX:
-            case VKD3DSIH_TEXM3x3VSPEC:
-            case VKD3DSIH_TEXREG2AR:
-            case VKD3DSIH_TEXREG2GB:
-            case VKD3DSIH_TEXREG2RGB:
-                vkd3d_shader_error(ctx->message_context, &ins->location,
-                        VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
-                        "Aborting due to not yet implemented feature: "
-                        "Combined sampler instruction %#x.", ins->opcode);
-                return VKD3D_ERROR_NOT_IMPLEMENTED;
-
-            default:
-                break;
-        }
-    }
-
-    return VKD3D_OK;
-}
-
 struct cf_flattener_if_info
 {
     struct vkd3d_shader_src_param *false_param;
@@ -6710,7 +6706,6 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
         vsir_transform(&ctx, vsir_program_normalise_io_registers);
         vsir_transform(&ctx, vsir_program_normalise_flat_constants);
         vsir_transform(&ctx, vsir_program_remove_dead_code);
-        vsir_transform(&ctx, vsir_program_normalise_combined_samplers);
 
         if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL
                 && compile_info->target_type != VKD3D_SHADER_TARGET_MSL)