diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h
index c9c879b98402e8eb578c94a7bbaa7a890bea222b..1278b45750490165135c78875a6ac602a6b96620 100644
--- a/include/vkd3d_shader.h
+++ b/include/vkd3d_shader.h
@@ -126,6 +126,60 @@ struct vkd3d_shader_scan_info
 HRESULT vkd3d_shader_scan_dxbc(const struct vkd3d_shader_code *dxbc,
         struct vkd3d_shader_scan_info *scan_info);
 
+enum vkd3d_component_type
+{
+    VKD3D_TYPE_VOID    = 0,
+    VKD3D_TYPE_UINT    = 1,
+    VKD3D_TYPE_INT     = 2,
+    VKD3D_TYPE_FLOAT   = 3,
+    VKD3D_TYPE_BOOL,
+    VKD3D_TYPE_COUNT,
+};
+
+enum vkd3d_sysval_semantic
+{
+    VKD3D_SV_POSITION                  = 1,
+    VKD3D_SV_CLIP_DISTANCE             = 2,
+    VKD3D_SV_CULL_DISTANCE             = 3,
+    VKD3D_SV_RENDER_TARGET_ARRAY_INDEX = 4,
+    VKD3D_SV_VIEWPORT_ARRAY_INDEX      = 5,
+    VKD3D_SV_VERTEX_ID                 = 6,
+    VKD3D_SV_PRIMITIVE_ID              = 7,
+    VKD3D_SV_INSTANCE_ID               = 8,
+    VKD3D_SV_IS_FRONT_FACE             = 9,
+    VKD3D_SV_SAMPLE_INDEX              = 10,
+    VKD3D_SV_TESS_FACTOR_QUADEDGE      = 11,
+    VKD3D_SV_TESS_FACTOR_QUADINT       = 12,
+    VKD3D_SV_TESS_FACTOR_TRIEDGE       = 13,
+    VKD3D_SV_TESS_FACTOR_TRIINT        = 14,
+    VKD3D_SV_TESS_FACTOR_LINEDET       = 15,
+    VKD3D_SV_TESS_FACTOR_LINEDEN       = 16,
+};
+
+struct vkd3d_shader_signature_element
+{
+    const char *semantic_name;
+    unsigned int semantic_index;
+    unsigned int stream_index;
+    enum vkd3d_sysval_semantic sysval_semantic;
+    enum vkd3d_component_type component_type;
+    unsigned int register_index;
+    DWORD mask;
+};
+
+struct vkd3d_shader_signature
+{
+    struct vkd3d_shader_signature_element *elements;
+    unsigned int element_count;
+};
+
+HRESULT vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_signature *signature);
+struct vkd3d_shader_signature_element *vkd3d_shader_find_signature_element(
+        const struct vkd3d_shader_signature *signature, const char *semantic_name,
+        unsigned int semantic_index, unsigned int stream_index);
+void vkd3d_shader_free_shader_signature(struct vkd3d_shader_signature *signature);
+
 #ifdef __cplusplus
 }
 #endif  /* __cplusplus */
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c
index 66c9ab0c0d5365c5b8284aaf83a71bfb2edfcbde..9067bfa4e688cb46e782ed7edf4e6f45201fd49e 100644
--- a/libs/vkd3d-shader/dxbc.c
+++ b/libs/vkd3d-shader/dxbc.c
@@ -19,9 +19,6 @@
 
 #include "vkd3d_shader_private.h"
 
-#include <string.h>
-#include <strings.h>
-
 #define VKD3D_SM4_INSTRUCTION_MODIFIER        (0x1u << 31)
 
 #define VKD3D_SM4_MODIFIER_AOFFIMMI           0x1
@@ -1277,13 +1274,13 @@ void *shader_sm4_init(const DWORD *byte_code, size_t byte_code_size,
     {
         struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
 
-        if (e->register_idx >= ARRAY_SIZE(priv->output_map))
+        if (e->register_index >= ARRAY_SIZE(priv->output_map))
         {
-            WARN("Invalid output index %u.\n", e->register_idx);
+            WARN("Invalid output index %u.\n", e->register_index);
             continue;
         }
 
-        priv->output_map[e->register_idx] = e->semantic_idx;
+        priv->output_map[e->register_index] = e->semantic_index;
     }
 
     list_init(&priv->src_free);
@@ -1906,9 +1903,9 @@ static HRESULT shader_parse_signature(DWORD tag, const char *data, DWORD data_si
         DWORD name_offset;
 
         if (tag == TAG_OSG5)
-            read_dword(&ptr, &e[i].stream_idx);
+            read_dword(&ptr, &e[i].stream_index);
         else
-            e[i].stream_idx = 0;
+            e[i].stream_index = 0;
         read_dword(&ptr, &name_offset);
         if (!(e[i].semantic_name = shader_get_string(data, data_size, name_offset)))
         {
@@ -1916,16 +1913,16 @@ static HRESULT shader_parse_signature(DWORD tag, const char *data, DWORD data_si
             vkd3d_free(e);
             return E_INVALIDARG;
         }
-        read_dword(&ptr, &e[i].semantic_idx);
+        read_dword(&ptr, &e[i].semantic_index);
         read_dword(&ptr, &e[i].sysval_semantic);
         read_dword(&ptr, &e[i].component_type);
-        read_dword(&ptr, &e[i].register_idx);
+        read_dword(&ptr, &e[i].register_index);
         read_dword(&ptr, &e[i].mask);
 
         TRACE("Stream: %u, semantic: %s, semantic idx: %u, sysval_semantic %#x, "
                 "type %u, register idx: %u, use_mask %#x, input_mask %#x.\n",
-                e[i].stream_idx, debugstr_a(e[i].semantic_name), e[i].semantic_idx, e[i].sysval_semantic,
-                e[i].component_type, e[i].register_idx, (e[i].mask >> 8) & 0xff, e[i].mask & 0xff);
+                e[i].stream_index, debugstr_a(e[i].semantic_name), e[i].semantic_index, e[i].sysval_semantic,
+                e[i].component_type, e[i].register_index, (e[i].mask >> 8) & 0xff, e[i].mask & 0xff);
     }
 
     s->elements = e;
@@ -1934,25 +1931,35 @@ static HRESULT shader_parse_signature(DWORD tag, const char *data, DWORD data_si
     return S_OK;
 }
 
-struct vkd3d_shader_signature_element *shader_find_signature_element(const struct vkd3d_shader_signature *s,
-        const char *semantic_name, unsigned int semantic_idx, unsigned int stream_idx)
+static HRESULT isgn_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
 {
-    struct vkd3d_shader_signature_element *e = s->elements;
-    unsigned int i;
+    struct vkd3d_shader_signature *is = ctx;
+
+    if (tag != TAG_ISGN)
+        return S_OK;
 
-    for (i = 0; i < s->element_count; ++i)
+    if (is->elements)
     {
-        if (!strcasecmp(e[i].semantic_name, semantic_name) && e[i].semantic_idx == semantic_idx
-                && e[i].stream_idx == stream_idx)
-            return &e[i];
+        FIXME("Multiple input signatures.\n");
+        vkd3d_shader_free_shader_signature(is);
     }
-
-    return NULL;
+    return shader_parse_signature(tag, data, data_size, is);
 }
 
-static void shader_free_signature(struct vkd3d_shader_signature *s)
+HRESULT shader_parse_input_signature(const void *dxbc, SIZE_T dxbc_length,
+        struct vkd3d_shader_signature *signature)
 {
-    vkd3d_free(s->elements);
+    HRESULT hr;
+
+    memset(signature, 0, sizeof(*signature));
+
+    if (FAILED(hr = parse_dxbc(dxbc, dxbc_length, isgn_handler, signature)))
+    {
+        ERR("Failed to parse input signature.\n");
+        return E_FAIL;
+    }
+
+    return S_OK;
 }
 
 static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *context)
@@ -2015,9 +2022,9 @@ static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *
 
 void free_shader_desc(struct vkd3d_shader_desc *desc)
 {
-    shader_free_signature(&desc->input_signature);
-    shader_free_signature(&desc->output_signature);
-    shader_free_signature(&desc->patch_constant_signature);
+    vkd3d_shader_free_shader_signature(&desc->input_signature);
+    vkd3d_shader_free_shader_signature(&desc->output_signature);
+    vkd3d_shader_free_shader_signature(&desc->patch_constant_signature);
 }
 
 HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length,
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index fd102cc44c8f2211604f6f1d9eef65385742114a..d927909078ba4f19279fcc2eb1ff792f96eca86c 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -2636,7 +2636,7 @@ static const struct vkd3d_shader_signature_element *vkd3d_find_signature_element
 
     for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
     {
-        if (signature->elements[signature_idx].register_idx == reg->idx[0].offset
+        if (signature->elements[signature_idx].register_index == reg->idx[0].offset
                 && (signature->elements[signature_idx].mask & 0xff) == write_mask)
         {
             if (signature_element_index)
@@ -5474,7 +5474,7 @@ static void vkd3d_dxbc_compiler_emit_output_setup_function(struct vkd3d_dxbc_com
     for (i = 0; i < signature->element_count; ++i)
     {
         variable_idx = vkd3d_dxbc_compiler_get_output_variable_index(compiler,
-                signature->elements[i].register_idx);
+                signature->elements[i].register_index);
 
         if (!param_id[variable_idx])
             continue;
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c
index 25a7d1956782df6193aa650132511e64ba3f1f84..6522dd69258d116f231e080cd667d357d4c567d8 100644
--- a/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -216,3 +216,41 @@ void vkd3d_shader_free_root_signature(D3D12_ROOT_SIGNATURE_DESC *root_signature)
 
     memset(root_signature, 0, sizeof(*root_signature));
 }
+
+HRESULT vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
+        struct vkd3d_shader_signature *signature)
+{
+    TRACE("dxbc {%p, %zu}, signature %p.\n", dxbc->code, dxbc->size, signature);
+
+    return shader_parse_input_signature(dxbc->code, dxbc->size, signature);
+}
+
+struct vkd3d_shader_signature_element *vkd3d_shader_find_signature_element(
+        const struct vkd3d_shader_signature *signature, const char *semantic_name,
+        unsigned int semantic_index, unsigned int stream_index)
+{
+    struct vkd3d_shader_signature_element *e = signature->elements;
+    unsigned int i;
+
+    TRACE("signature %p, semantic_name %s, semantic_index %u, stream_index %u.\n",
+            signature, debugstr_a(semantic_name), semantic_index, stream_index);
+
+    e = signature->elements;
+    for (i = 0; i < signature->element_count; ++i)
+    {
+        if (!strcasecmp(e[i].semantic_name, semantic_name)
+                && e[i].semantic_index == semantic_index
+                && e[i].stream_index == stream_index)
+            return &e[i];
+    }
+
+    return NULL;
+}
+
+void vkd3d_shader_free_shader_signature(struct vkd3d_shader_signature *signature)
+{
+    TRACE("signature %p.\n", signature);
+
+    vkd3d_free(signature->elements);
+    signature->elements = NULL;
+}
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index 0f66f0f58bf9fd60bddfe01d5d7e4750402bb9e2..a3d2b4ad22986058dfa9176db8ce2013fedef62d 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -55,6 +55,8 @@
 #include <inttypes.h>
 #include <limits.h>
 #include <stdbool.h>
+#include <string.h>
+#include <strings.h>
 
 #define VKD3D_VEC4_SIZE 4
 
@@ -352,16 +354,6 @@ enum vkd3d_shader_register_type
     VKD3DSPR_GSINSTID,
 };
 
-enum vkd3d_component_type
-{
-    VKD3D_TYPE_VOID    = 0,
-    VKD3D_TYPE_UINT    = 1,
-    VKD3D_TYPE_INT     = 2,
-    VKD3D_TYPE_FLOAT   = 3,
-    VKD3D_TYPE_BOOL,
-    VKD3D_TYPE_COUNT,
-};
-
 enum vkd3d_shader_resource_type
 {
     VKD3D_SHADER_RESOURCE_NONE,
@@ -621,26 +613,6 @@ struct vkd3d_shader_semantic
     struct vkd3d_shader_dst_param reg;
 };
 
-enum vkd3d_sysval_semantic
-{
-    VKD3D_SV_POSITION                     = 1,
-    VKD3D_SV_CLIP_DISTANCE                = 2,
-    VKD3D_SV_CULL_DISTANCE                = 3,
-    VKD3D_SV_RENDER_TARGET_ARRAY_INDEX    = 4,
-    VKD3D_SV_VIEWPORT_ARRAY_INDEX         = 5,
-    VKD3D_SV_VERTEX_ID                    = 6,
-    VKD3D_SV_PRIMITIVE_ID                 = 7,
-    VKD3D_SV_INSTANCE_ID                  = 8,
-    VKD3D_SV_IS_FRONT_FACE                = 9,
-    VKD3D_SV_SAMPLE_INDEX                 = 10,
-    VKD3D_SV_TESS_FACTOR_QUADEDGE         = 11,
-    VKD3D_SV_TESS_FACTOR_QUADINT          = 12,
-    VKD3D_SV_TESS_FACTOR_TRIEDGE          = 13,
-    VKD3D_SV_TESS_FACTOR_TRIINT           = 14,
-    VKD3D_SV_TESS_FACTOR_LINEDET          = 15,
-    VKD3D_SV_TESS_FACTOR_LINEDEN          = 16,
-};
-
 enum vkd3d_shader_input_sysval_semantic
 {
     VKD3D_SIV_NONE                         = 0,
@@ -668,23 +640,6 @@ enum vkd3d_shader_input_sysval_semantic
     VKD3D_SIV_LINE_DENSITY_TESS_FACTOR     = 22,
 };
 
-struct vkd3d_shader_signature_element
-{
-    const char *semantic_name;
-    unsigned int semantic_idx;
-    unsigned int stream_idx;
-    enum vkd3d_sysval_semantic sysval_semantic;
-    enum vkd3d_component_type component_type;
-    unsigned int register_idx;
-    DWORD mask;
-};
-
-struct vkd3d_shader_signature
-{
-    UINT element_count;
-    struct vkd3d_shader_signature_element *elements;
-};
-
 struct vkd3d_shader_desc
 {
     const DWORD *byte_code;
@@ -815,10 +770,11 @@ BOOL shader_sm4_is_end(void *data, const DWORD **ptr) DECLSPEC_HIDDEN;
 
 HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length,
         struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
-struct vkd3d_shader_signature_element *shader_find_signature_element(const struct vkd3d_shader_signature *s,
-        const char *semantic_name, unsigned int semantic_idx, unsigned int stream_idx) DECLSPEC_HIDDEN;
 void free_shader_desc(struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
 
+HRESULT shader_parse_input_signature(const void *dxbc, SIZE_T dxbc_length,
+        struct vkd3d_shader_signature *signature) DECLSPEC_HIDDEN;
+
 struct vkd3d_dxbc_compiler;
 
 struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,