diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c
index 4fbce3937070aac397905acbd00fd7ca7d5b8d31..d4e612c9d36ee0d5e8a1e47cc76e3e362b062851 100644
--- a/libs/vkd3d-shader/fx.c
+++ b/libs/vkd3d-shader/fx.c
@@ -725,6 +725,28 @@ static const struct rhs_named_value fx_2_lighttype_values[] =
     { NULL }
 };
 
+static const struct rhs_named_value fx_2_address_values[] =
+{
+    { "WRAP", 1 },
+    { "MIRROR", 2 },
+    { "CLAMP", 3 },
+    { "BORDER", 4 },
+    { "MIRROR_ONCE", 5 },
+    { NULL }
+};
+
+static const struct rhs_named_value fx_2_filter_values[] =
+{
+    { "NONE", 0 },
+    { "POINT", 1 },
+    { "LINEAR", 2 },
+    { "ANISOTROPIC", 3 },
+    { "PYRAMIDALQUAD", 6 },
+    { "GAUSSIANQUAD", 7 },
+    { "CONVOLUTIONMONO", 8 },
+    { NULL }
+};
+
 static const struct fx_2_state
 {
     const char *name;
@@ -895,6 +917,38 @@ fx_2_states[] =
 
     { "VertexShader",      HLSL_CLASS_SCALAR, FX_VERTEXSHADER, 1, 1, 146 },
     { "PixelShader",       HLSL_CLASS_SCALAR, FX_PIXELSHADER,  1, 1, 147 },
+
+    { "VertexShaderConstantF", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 148 },
+    { "VertexShaderConstantB", HLSL_CLASS_SCALAR, FX_BOOL,  1, ~0u-1, 149 },
+    { "VertexShaderConstantI", HLSL_CLASS_SCALAR, FX_UINT,  1, ~0u-1, 150 },
+    { "VertexShaderConstant",  HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 151 },
+    { "VertexShaderConstant1", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 152 },
+    { "VertexShaderConstant2", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 153 },
+    { "VertexShaderConstant3", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 154 },
+    { "VertexShaderConstant4", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 155 },
+
+    { "PixelShaderConstantF", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 156 },
+    { "PixelShaderConstantB", HLSL_CLASS_SCALAR, FX_BOOL,  1, ~0u-1, 157 },
+    { "PixelShaderConstantI", HLSL_CLASS_SCALAR, FX_UINT,  1, ~0u-1, 158 },
+    { "PixelShaderConstant",  HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 159 },
+    { "PixelShaderConstant1", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 160 },
+    { "PixelShaderConstant2", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 161 },
+    { "PixelShaderConstant3", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 162 },
+    { "PixelShaderConstant4", HLSL_CLASS_SCALAR, FX_FLOAT, 1, ~0u-1, 163 },
+
+    { "Texture",           HLSL_CLASS_SCALAR, FX_TEXTURE, 1, 1, 164 },
+    { "AddressU",          HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 165, fx_2_address_values },
+    { "AddressV",          HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 166, fx_2_address_values },
+    { "AddressW",          HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 167, fx_2_address_values },
+    { "BorderColor",       HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 168 },
+    { "MagFilter",         HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 169, fx_2_filter_values },
+    { "MinFilter",         HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 170, fx_2_filter_values },
+    { "MipFilter",         HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 171, fx_2_filter_values },
+    { "MipMapLodBias",     HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 172 },
+    { "MaxMipLevel",       HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 173 },
+    { "MaxAnisotropy",     HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 174 },
+    { "SRBTexture",        HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 175 },
+    { "ElementIndex",      HLSL_CLASS_SCALAR, FX_UINT,    1, 1, 176 },
 };
 
 static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
@@ -3644,6 +3698,40 @@ static bool is_fx_2_sampler(uint32_t type)
             || type == D3DXPT_SAMPLERCUBE;
 }
 
+static void fx_parse_fx_2_assignment(struct fx_parser *parser, const struct fx_assignment *entry);
+
+static void parse_fx_2_sampler(struct fx_parser *parser, uint32_t element_count,
+        uint32_t offset)
+{
+    struct fx_assignment entry;
+    uint32_t count;
+
+    element_count = max(element_count, 1);
+
+    vkd3d_string_buffer_printf(&parser->buffer, "\n");
+    for (uint32_t i = 0; i < element_count; ++i)
+    {
+        fx_parser_read_unstructured(parser, &count, offset, sizeof(count));
+        offset += sizeof(count);
+
+        parse_fx_start_indent(parser);
+        parse_fx_print_indent(parser);
+        vkd3d_string_buffer_printf(&parser->buffer, "{\n");
+        parse_fx_start_indent(parser);
+        for (uint32_t j = 0; j < count; ++j, offset += sizeof(entry))
+        {
+            fx_parser_read_unstructured(parser, &entry, offset, sizeof(entry));
+
+            parse_fx_print_indent(parser);
+            fx_parse_fx_2_assignment(parser, &entry);
+        }
+        parse_fx_end_indent(parser);
+        parse_fx_print_indent(parser);
+        vkd3d_string_buffer_printf(&parser->buffer, "},\n");
+        parse_fx_end_indent(parser);
+    }
+}
+
 static void fx_parse_fx_2_initial_value(struct fx_parser *parser, uint32_t param, uint32_t value)
 {
     struct fx_2_var
@@ -3672,8 +3760,7 @@ static void fx_parse_fx_2_initial_value(struct fx_parser *parser, uint32_t param
     if (var.class == D3DXPC_OBJECT)
     {
         if (is_fx_2_sampler(var.type))
-            fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED,
-                    "Parsing sampler initializers is not supported.");
+            parse_fx_2_sampler(parser, var.element_count, value);
         else
             parse_fx_2_object_value(parser, var.element_count, var.type, value);
     }
@@ -3714,24 +3801,22 @@ static void fx_parse_fx_2_annotations(struct fx_parser *parser, uint32_t count)
     vkd3d_string_buffer_printf(&parser->buffer, ">");
 }
 
-static void fx_parse_fx_2_assignment(struct fx_parser *parser)
+static void fx_parse_fx_2_assignment(struct fx_parser *parser, const struct fx_assignment *entry)
 {
     const struct rhs_named_value *named_value = NULL;
     const struct fx_2_state *state = NULL;
-    struct fx_assignment entry;
 
-    fx_parser_read_u32s(parser, &entry, sizeof(entry));
-    if (entry.id <= ARRAY_SIZE(fx_2_states))
+    if (entry->id <= ARRAY_SIZE(fx_2_states))
     {
-        state = &fx_2_states[entry.id];
+        state = &fx_2_states[entry->id];
 
         vkd3d_string_buffer_printf(&parser->buffer, "%s", state->name);
         if (state->array_size > 1)
-            vkd3d_string_buffer_printf(&parser->buffer, "[%u]", entry.lhs_index);
+            vkd3d_string_buffer_printf(&parser->buffer, "[%u]", entry->lhs_index);
     }
     else
     {
-        vkd3d_string_buffer_printf(&parser->buffer, "<unrecognized state %u>", entry.id);
+        vkd3d_string_buffer_printf(&parser->buffer, "<unrecognized state %u>", entry->id);
     }
     vkd3d_string_buffer_printf(&parser->buffer, " = ");
 
@@ -3740,7 +3825,7 @@ static void fx_parse_fx_2_assignment(struct fx_parser *parser)
         const struct rhs_named_value *ptr = state->values;
         uint32_t value;
 
-        fx_parser_read_unstructured(parser, &value, entry.value, sizeof(value));
+        fx_parser_read_unstructured(parser, &value, entry->value, sizeof(value));
 
         while (ptr->name)
         {
@@ -3757,13 +3842,27 @@ static void fx_parse_fx_2_assignment(struct fx_parser *parser)
     {
         vkd3d_string_buffer_printf(&parser->buffer, "%s /* %u */", named_value->name, named_value->value);
     }
-    else if (state && (state->type == FX_UINT || state->type == FX_FLOAT))
+    else if (state)
     {
-        uint32_t offset = entry.type;
-        unsigned int size;
+        if (state->type == FX_UINT || state->type == FX_FLOAT)
+        {
+            uint32_t offset = entry->type;
+            unsigned int size;
+
+            size = fx_get_fx_2_type_size(parser, &offset);
+            parse_fx_2_numeric_value(parser, entry->value, size, entry->type);
+        }
+        else if (state->type == FX_VERTEXSHADER || state->type == FX_PIXELSHADER)
+        {
+            uint32_t id;
 
-        size = fx_get_fx_2_type_size(parser, &offset);
-        parse_fx_2_numeric_value(parser, entry.value, size, entry.type);
+            fx_parser_read_unstructured(parser, &id, entry->value, sizeof(id));
+            vkd3d_string_buffer_printf(&parser->buffer, "<object id %u>", id);
+        }
+        else
+        {
+            vkd3d_string_buffer_printf(&parser->buffer, "<ignored>");
+        }
     }
     else
     {
@@ -3820,8 +3919,11 @@ static void fx_parse_fx_2_technique(struct fx_parser *parser)
         parse_fx_start_indent(parser);
         for (uint32_t j = 0; j < pass.assignment_count; ++j)
         {
+            struct fx_assignment entry;
+
             parse_fx_print_indent(parser);
-            fx_parse_fx_2_assignment(parser);
+            fx_parser_read_u32s(parser, &entry, sizeof(entry));
+            fx_parse_fx_2_assignment(parser, &entry);
         }
         parse_fx_end_indent(parser);
 
@@ -3858,10 +3960,59 @@ static void fx_2_parse_parameters(struct fx_parser *parser, uint32_t count)
         vkd3d_string_buffer_printf(&parser->buffer, "\n");
 }
 
+static void fx_2_parse_shader_blob(struct fx_parser *parser, const void *data, uint32_t data_size)
+{
+    struct vkd3d_shader_compile_info info = { 0 };
+    struct vkd3d_shader_code output;
+    const char *p, *q, *end;
+    int ret;
+
+    static const struct vkd3d_shader_compile_option options[] =
+    {
+        {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_15},
+    };
+
+    info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO;
+    info.source.code = data;
+    info.source.size = data_size;
+    info.source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE;
+    info.target_type = VKD3D_SHADER_TARGET_D3D_ASM;
+    info.options = options;
+    info.option_count = ARRAY_SIZE(options);
+    info.log_level = VKD3D_SHADER_LOG_INFO;
+
+    if ((ret = vkd3d_shader_compile(&info, &output, NULL)) < 0)
+    {
+        fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_INVALID_DATA,
+                "Failed to disassemble shader blob.");
+        return;
+    }
+    parse_fx_print_indent(parser);
+    vkd3d_string_buffer_printf(&parser->buffer, "asm {\n");
+
+    parse_fx_start_indent(parser);
+
+    end = (const char *)output.code + output.size;
+    for (p = output.code; p < end; p = q)
+    {
+        if (!(q = memchr(p, '\n', end - p)))
+            q = end;
+        else
+            ++q;
+
+        parse_fx_print_indent(parser);
+        vkd3d_string_buffer_printf(&parser->buffer, "%.*s", (int)(q - p), p);
+    }
+
+    parse_fx_end_indent(parser);
+    parse_fx_print_indent(parser);
+    vkd3d_string_buffer_printf(&parser->buffer, "}");
+}
+
 static void fx_parse_fx_2_data_blob(struct fx_parser *parser)
 {
     uint32_t id, size;
-    const char *str;
+    const void *data;
 
     id = fx_parser_read_u32(parser);
     size = fx_parser_read_u32(parser);
@@ -3882,13 +4033,23 @@ static void fx_parse_fx_2_data_blob(struct fx_parser *parser)
             case D3DXPT_VERTEXSHADER:
                 vkd3d_string_buffer_printf(&parser->buffer, "%s object %u size %u bytes%s\n",
                         fx_2_types[type], id, size, size ? ":" : ",");
-                if (size && type == D3DXPT_STRING)
+
+                if (size)
                 {
-                    parse_fx_start_indent(parser);
-                    parse_fx_print_indent(parser);
-                    str = fx_parser_get_ptr(parser, size);
-                    vkd3d_string_buffer_printf(&parser->buffer, "\"%.*s\"\n", size, str);
-                    parse_fx_end_indent(parser);
+                    data = fx_parser_get_ptr(parser, size);
+
+                    if (type == D3DXPT_STRING)
+                    {
+                        parse_fx_start_indent(parser);
+                        parse_fx_print_indent(parser);
+                        vkd3d_string_buffer_printf(&parser->buffer, "\"%.*s\"", size, (const char *)data);
+                        parse_fx_end_indent(parser);
+                    }
+                    else if (type == D3DXPT_PIXELSHADER || type == D3DXPT_VERTEXSHADER)
+                    {
+                        fx_2_parse_shader_blob(parser, data, size);
+                    }
+                    vkd3d_string_buffer_printf(&parser->buffer, "\n");
                 }
                 break;
             default:
@@ -3903,9 +4064,62 @@ static void fx_parse_fx_2_data_blob(struct fx_parser *parser)
     fx_parser_skip(parser, align(size, 4));
 }
 
+static void fx_dump_blob(struct fx_parser *parser, const void *blob, uint32_t size)
+{
+    const uint32_t *data = (const uint32_t *)blob;
+    unsigned int i, j, n;
+
+    size /= sizeof(*data);
+    i = 0;
+    while (i < size)
+    {
+        parse_fx_print_indent(parser);
+        n = min(size - i, 8);
+        for (j = 0; j < n; ++j)
+            vkd3d_string_buffer_printf(&parser->buffer, "0x%08x,", data[i + j]);
+        i += n;
+        vkd3d_string_buffer_printf(&parser->buffer, "\n");
+    }
+}
+
+static void fx_parse_fx_2_complex_state(struct fx_parser *parser)
+{
+    struct
+    {
+        uint32_t technique;
+        uint32_t index;
+        uint32_t element;
+        uint32_t state;
+        uint32_t value_type;
+    } state;
+    const void *data;
+    uint32_t size;
+
+    fx_parser_read_u32s(parser, &state, sizeof(state));
+
+    if (state.technique == ~0u)
+    {
+        vkd3d_string_buffer_printf(&parser->buffer, "parameter %u[%u], state %u =\n",
+                state.index, state.element, state.state);
+    }
+    else
+    {
+        vkd3d_string_buffer_printf(&parser->buffer, "technique %u, pass %u, state %u =\n",
+                state.technique, state.index, state.state);
+    }
+
+    size = fx_parser_read_u32(parser);
+    data = fx_parser_get_ptr(parser, size);
+
+    parse_fx_print_indent(parser);
+    vkd3d_string_buffer_printf(&parser->buffer, "blob size %u\n", size);
+    fx_dump_blob(parser, data, size);
+    fx_parser_skip(parser, align(size, 4));
+}
+
 static void fx_2_parse(struct fx_parser *parser)
 {
-    uint32_t i, size, parameter_count, technique_count, blob_count;
+    uint32_t i, size, parameter_count, technique_count, blob_count, state_count;
 
     fx_parser_skip(parser, sizeof(uint32_t)); /* Version */
     size = fx_parser_read_u32(parser);
@@ -3931,13 +4145,20 @@ static void fx_2_parse(struct fx_parser *parser)
         fx_parse_fx_2_technique(parser);
 
     blob_count = fx_parser_read_u32(parser);
-    fx_parser_read_u32(parser); /* Resource count */
+    state_count = fx_parser_read_u32(parser);
 
     vkd3d_string_buffer_printf(&parser->buffer, "object data {\n");
     parse_fx_start_indent(parser);
     for (i = 0; i < blob_count; ++i)
         fx_parse_fx_2_data_blob(parser);
     parse_fx_end_indent(parser);
+    vkd3d_string_buffer_printf(&parser->buffer, "}\n\n");
+
+    vkd3d_string_buffer_printf(&parser->buffer, "state data {\n");
+    parse_fx_start_indent(parser);
+    for (i = 0; i < state_count; ++i)
+        fx_parse_fx_2_complex_state(parser);
+    parse_fx_end_indent(parser);
     vkd3d_string_buffer_printf(&parser->buffer, "}\n");
 }